在curl或wget之后,输出重定向中未迭代Bash变量

时间:2019-04-13 21:28:11

标签: linux bash shell curl 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封装到子外壳( ... )中是没有帮助的。

这2个班轮当然有效:

((i++))
curl -s 'https://www.google.com' > "./out_curl_${i}.txt"

谢谢您的提示。

1 个答案:

答案 0 :(得分:2)

处理重定向通常是在分支子进程之后进行的,但必须在使用execve()将控制权从外壳移交给新的可执行文件的情况下进行。 (在您的情况下为curlwget)在该进程中运行。

因为您已经fork(),对变量的更改是在新流程的上下文中发生的,并且不会传播回父级。

这不适用于默认的echo,因为它是内置的shell,因此是进程内的(根本不需要fork),但是确实 em>适用于以这种方式实现的外壳上的/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代替。