如何将输入传递给Bash while循环并在循环结束后保留​​变量

Wak*_*nka 80 bash stdin pipe while-loop

Bash允许使用: cat <(echo "$FILECONTENT")

Bash还允许使用: while read i; do echo $i; done </etc/passwd

结合前两个可以使用: echo $FILECONTENT | while read i; do echo $i; done

最后一个问题是它创建了子shell,而在while循环结束后,变量i不再被访问.

我的问题是:

如何实现这样的目标:while read i; do echo $i; done <(echo "$FILECONTENT")或者换句话说:我怎样才能确定i循环中存活?

请注意我知道封闭while语句{}但这并不能解决问题(想象一下你想在函数中使用while循环并返回i变量)

Jon*_*ler 103

过程替换的正确表示法是:

while read i; do echo $i; done < <(echo "$FILECONTENT")
Run Code Online (Sandbox Code Playgroud)

i循环终止时,循环中分配的最后一个值可用.另一种选择是:

echo $FILECONTENT | 
{
while read i; do echo $i; done
...do other things using $i here...
}
Run Code Online (Sandbox Code Playgroud)

大括号是一个I/O分组操作,本身不会创建子shell.在这种情况下,它们是管道的一部分,因此作为子shell运行,但它是因为而|不是{ ... }.你在这个问题中提到了这一点.AFAIK,你可以从这些函数内部返回.


Bash还提供shopt内置版本,其中许多选项之一是:

lastpipe

如果设置,并且作业控制未激活,则shell将运行当前shell环境中未在后台执行的管道的最后一个命令.

因此,在脚本中使用这样的东西会使sum循环后修改可用:

FILECONTENT="12 Name
13 Number
14 Information"
shopt -s lastpipe   # Comment this out to see the alternative behaviour
sum=0
echo "$FILECONTENT" |
while read number name; do ((sum+=$number)); done
echo $sum
Run Code Online (Sandbox Code Playgroud)

在命令行执行此操作通常会违反"作业控制未激活"(即,在命令行,作业控制处于活动状态).不使用脚本进行测试失败.

另外,正如Gareth Rees在他的回答中所指出的,你有时可以使用这里的字符串:

while read i; do echo $i; done <<< "$FILECONTENT"
Run Code Online (Sandbox Code Playgroud)

这不需要shopt; 您可以使用它保存进程.

  • 原谅我的无知。我知道这是正确的解决方案,并且我已将其标记为答案,因此它对我有用。但现在当我运行“while read i;”时 回显 $i; 完成 &lt; &lt;(cat /etc/passwd); echo $i` 它没有返回最后一行两次。我做错了什么? (2认同)

Gar*_*ees 27

Jonathan Leffler解释了如何使用进程替换来执行您想要的操作,但另一种可能性是使用here字符串:

while read i; do echo "$i"; done <<<"$FILECONTENT"
Run Code Online (Sandbox Code Playgroud)

这节省了一个过程.