在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
封装到子外壳( ... )
中是没有帮助的。
这2个班轮当然有效:
((i++))
curl -s 'https://www.google.com' > "./out_curl_${i}.txt"
谢谢您的提示。
答案 0 :(得分:2)
处理重定向通常是在分支子进程之后进行的,但必须在使用execve()
将控制权从外壳移交给新的可执行文件的情况下进行。 (在您的情况下为curl
或wget
)在该进程中运行。
因为您已经fork()
,对变量的更改是在新流程的上下文中发生的,并且不会传播回父级。
这不适用于默认的echo
,因为它是内置的shell,因此是进程内的(根本不需要fork
),但是确实
/bin/echo
(POSIX标准既不禁止也不要求)。
此问题的一个更简单的复制器-表明它适用于 all 所有非内置命令-由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
{ ...; }
构造对整个命令块执行重定向,并因此在分支过程中执行 之前的重定向,该子过程将由/bin/echo
代替。