gpt4 book ai didi

bash:循环的管道输出似乎改变了循环内的范围 - 为什么?

转载 作者:行者123 更新时间:2023-11-29 09:21:29 26 4
gpt4 key购买 nike

我注意到,如果我对循环的输出进行管道传输,bash for 循环中的变量范围似乎会发生变化。

例如,这里的g在循环后保持不变:

$ g=bing; for f in foo; do g=fing; echo g in loop: $g; done; echo g after $g;
g in loop: fing
g after fing

而在这里,循环期间的更改被遗忘了:

$ g=bing; for f in foo; do g=fing; echo g in loop: $g; done | cat; echo g after $g;
g in loop: fing
g after bing

管道接收器中 g 的值也来自“外部”上下文:

$ g=bing; for f in foo; do g=fing; echo g in loop: $g; done | (cat; echo in pipe $g;); echo g after $g;
g in loop: fing
in pipe bing
g after bing

这是怎么回事?

最佳答案

来自 bash 手册页

Each command in a pipeline is executed as a separate process (i.e., in a subshell).

这意味着管道的两侧都在子 shell 中运行。

来自 http://www.tldp.org/LDP/abs/html/subshells.html

Variables in a subshell are not visible outside the block of code in the subshell. They are not accessible to the parent process, to the shell that launched the subshell. These are, in effect, variables local to the child process.

这意味着当管道结束时,对变量的所有更改都将丢失。


这是使用 BASH_SUBSHELL

对该理论的概念证明

BASH_SUBSHELL Incremented by one each time a subshell or subshell environment is spawned. The initial value is 0.

输入:

echo "before loop:$BASH_SUBSHELL"
for i in foo; do echo "in loop:$BASH_SUBSHELL"; done | (cat;echo "second pipe: $BASH_SUBSHELL")
echo "out of pipe: $BASH_SUBSHELL"

输出:

before loop:0
in loop:1
second pipe: 1
out of pipe: 0

如您所见,循环内部和管道的第二部分都在子外壳中运行,并且它们在管道的末端结束。


编辑 2

意识到这样做可能更清楚地显示运行的不同子 shell

bash <4.0

在旧的 bashes 中它不包含 $BASHPID 这实际上是查看子 shell 的 pid 的唯一方法,但你可以声明一个函数,如

GetPid(){ cut -d " " -f 4 /proc/self/stat; }

效果差不多

echo -n "before loop:";GetPid
for i in foo; do echo -n "in loop:";GetPid; done | (cat;echo -n "second pipe:";GetPid)
echo -n "out of pipe:";GetPid

bash 4.0+

 echo "before loop:$BASHPID"
for i in foo; do echo "in loop:$BASHPID"; done | (cat;echo "second pipe: $BASHPID")
echo "out of pipe: $BASHPID"

输出:

before loop:29985
in loop:12170
second pipe:12171
out of pipe:29985

正如您所看到的,这使得您在管道前后与原始变量位于同一个 shell 中变得更加清楚。
您的第三种情况也已解决,因为管道的两侧在不同的子外壳中运行,变量被重置为每个管道命令的父值,因此即使它仍然是相同的管道,也会在循环后恢复原状。

关于bash:循环的管道输出似乎改变了循环内的范围 - 为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30458681/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com