while 会在 bash 中生成子 shell 吗?

while 会在 bash 中生成子 shell 吗?

有人可以解释为什么这个脚本没有产生我期望的输出吗?

 #!/bin/bash
 #

var=0

ls -1 /tmp| while read file
do
     echo $file
     var=1
done

echo "var is $var"

我得到一个文件列表,然后是var is 0

为什么 var 不等于 1?是因为 while 循环产生了一个子 shell 吗?

答案1

管道确实如此。您可以自己检查,例如通过$BASHPID从 while 循环的内部和外部打印或执行以下操作:

ls | while read file; do
    sleep 100;
done

,停止它C-Z并检查psps --forest之后查看终端会话中的进程树。

您可以通过稍微不同的“管道”来避免子 shell:

var=0
while read file
do 
  echo $file; var=1
done < <(ls -1 /tmp/)

echo $var #=> 1

答案2

其他好的答案已经解释了不保留变量值的原因。如果您愿意,可以阅读有关此主题的有趣文章我在管道中的循环中设置变量。为什么循环结束后它们就消失了?或者,为什么我无法通过管道读取数据?

我只是想展示另一种循环文件的方法,这样您就ls根本不需要解析:

for file in /tmp/*
do
   echo "$file"
   var=1
done

就是这样!只需让/tmp/*Expand 即可提供目录中的所有内容/tmp

我猜你的脚本只是一些虚拟代码,而不是真正的代码。但如果你碰巧要检查是否/tmp包含某些值,你也可以说:

shopt -s nullglob
r=(/tmp/*)

然后计算数组中的元素:

echo ${#r[@]}

请注意,如果没有任何内容与此模式匹配,我过去常常shopt -s nullblog阻止/tmp/*扩展到文字字符串。/tmp/*

答案3

while不会,但管道会,因此while您的示例中的 将会在子 shell 中运行

人们通常可以使用循环来完成相同的任务for,其中生成要迭代的列表的命令在子 shell 中运行,而不是在循环中运行。例如:

for file in /tmp/*; do
    echo "$file"
    var=1
done

相关内容