Bash 变量在 curl 或 wget 后的输出重定向中没有迭代
Bash variable not iterated in output redirection after curl or wget
我在 curl
命令后的重定向中遇到了 Bash 变量的奇怪行为:
curl -s 'https://www.google.com' > "./out_curl_$((++i)).txt"
我创建了以下测试脚本 ./curl_test.sh
:
#!/bin/env bash
i=0
curl -s 'https://www.google.com' > "./out_curl_$((++i)).txt"
curl -s 'https://www.google.com' > "./out_curl_$((++i)).txt"
echo "This is i: ${i}"
ls -1 ./out_curl_*.txt
j=0
echo 'hello' > "./out_echo_$((++j)).txt"
echo 'hello' > "./out_echo_$((++j)).txt"
echo "This is j: ${j}"
ls -1 ./out_echo_*.txt
exit 0
输出:
$ ./curl_test.sh
This is i: 0
./out_curl_1.txt
This is j: 2
./out_echo_1.txt
./out_echo_2.txt
预期输出:
$ ./curl_test.sh
This is i: 2
./out_curl_1.txt
./out_curl_2.txt
This is j: 2
./out_echo_1.txt
./out_echo_2.txt
请问有人知道这是为什么吗?已经尝试过的:
wget
具有相同的行为:
wget -q -O - 'https://www.google.com' > "./out_wget_$((++k)).txt"
将curl
封装到子shell( ... )
中没有帮助。
这 2 个班轮当然有效:
((i++))
curl -s 'https://www.google.com' > "./out_curl_${i}.txt"
感谢您的任何提示。
处理重定向通常在 after 分叉子进程后完成,但必须在 before 使用 execve()
移交从 shell 到新的可执行文件(在你的情况下 curl
或 wget
)的控制在那个过程中是 运行。
因为您已经 fork()
了,变量的更改发生在新进程的上下文中,并且不会传播回父进程。
这不适用于默认的 echo
,因为它是内置的 shell,因此是在处理中(根本不需要 fork
),但它是否适用于 shell 上的 /bin/echo
以这种方式实施(POSIX 标准既不禁止也不要求)。
这个问题的一个更简单的复制器 -- 表明它适用于 所有 非内置命令 -- 下面是用 bash 3.2.57 生成的以及针对 4.4.23 转载:
$ i=0; echo >>"test$((++i)).tmp"; echo "$i"
1
$ i=0; /bin/echo >>"test$((++i)).tmp"; echo "$i"
0
如果您想解决此问题,可以通过对整个命令组执行重定向来实现:
$ i=0; { /bin/echo; } >>"test$((++i)).tmp"; echo "$i"
1
{ ...; }
构造对整个命令块执行重定向,因此在 分叉将被替换为 [=18 的子进程之前执行重定向 =].
我在 curl
命令后的重定向中遇到了 Bash 变量的奇怪行为:
curl -s 'https://www.google.com' > "./out_curl_$((++i)).txt"
我创建了以下测试脚本 ./curl_test.sh
:
#!/bin/env bash
i=0
curl -s 'https://www.google.com' > "./out_curl_$((++i)).txt"
curl -s 'https://www.google.com' > "./out_curl_$((++i)).txt"
echo "This is i: ${i}"
ls -1 ./out_curl_*.txt
j=0
echo 'hello' > "./out_echo_$((++j)).txt"
echo 'hello' > "./out_echo_$((++j)).txt"
echo "This is j: ${j}"
ls -1 ./out_echo_*.txt
exit 0
输出:
$ ./curl_test.sh
This is i: 0
./out_curl_1.txt
This is j: 2
./out_echo_1.txt
./out_echo_2.txt
预期输出:
$ ./curl_test.sh
This is i: 2
./out_curl_1.txt
./out_curl_2.txt
This is j: 2
./out_echo_1.txt
./out_echo_2.txt
请问有人知道这是为什么吗?已经尝试过的:
wget
具有相同的行为:
wget -q -O - 'https://www.google.com' > "./out_wget_$((++k)).txt"
将curl
封装到子shell( ... )
中没有帮助。
这 2 个班轮当然有效:
((i++))
curl -s 'https://www.google.com' > "./out_curl_${i}.txt"
感谢您的任何提示。
处理重定向通常在 after 分叉子进程后完成,但必须在 before 使用 execve()
移交从 shell 到新的可执行文件(在你的情况下 curl
或 wget
)的控制在那个过程中是 运行。
因为您已经 fork()
了,变量的更改发生在新进程的上下文中,并且不会传播回父进程。
这不适用于默认的 echo
,因为它是内置的 shell,因此是在处理中(根本不需要 fork
),但它是否适用于 shell 上的 /bin/echo
以这种方式实施(POSIX 标准既不禁止也不要求)。
这个问题的一个更简单的复制器 -- 表明它适用于 所有 非内置命令 -- 下面是用 bash 3.2.57 生成的以及针对 4.4.23 转载:
$ i=0; echo >>"test$((++i)).tmp"; echo "$i"
1
$ i=0; /bin/echo >>"test$((++i)).tmp"; echo "$i"
0
如果您想解决此问题,可以通过对整个命令组执行重定向来实现:
$ i=0; { /bin/echo; } >>"test$((++i)).tmp"; echo "$i"
1
{ ...; }
构造对整个命令块执行重定向,因此在 分叉将被替换为 [=18 的子进程之前执行重定向 =].