如何通过管道输入 Bash while 循环并在循环结束后保留​​变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19570413/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 00:21:39  来源:igfitidea点击:

How to pipe input to a Bash while loop and preserve variables after loop ends

bashwhile-loopstdinpipe

提问by Wakan Tanka

Bash allows to use: cat <(echo "$FILECONTENT")

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

Bash also allow to use: while read i; do echo $i; done </etc/passwd

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

to combine previous two this can be used: echo $FILECONTENT | while read i; do echo $i; done

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

The problem with last one is that it creates sub-shell and after the while loop ends variable icannot be accessed any more.

最后一个的问题是它创建了子外壳,并且在 while 循环结束后,i无法再访问变量。

My question is:

我的问题是:

How to achieve something like this: while read i; do echo $i; done <(echo "$FILECONTENT")or in other words: How can I be sure that isurvives while loop?

如何实现这样的事情:while read i; do echo $i; done <(echo "$FILECONTENT")或者换句话说:我怎么能确定在iwhile循环中幸存下来?

Please note that I am aware of enclosing while statement into {}but this does not solves the problem (imagine that you want use the while loop in function and return ivariable)

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

回答by Jonathan Leffler

The correct notation for Process Substitutionis:

进程替换的正确符号是:

while read i; do echo $i; done < <(echo "$FILECONTENT")

The last value of iassigned in the loop is then available when the loop terminates. An alternative is:

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

echo $FILECONTENT | 
{
while read i; do echo $i; done
...do other things using $i here...
}

The braces are an I/O grouping operation and do not themselves create a subshell. In this context, they are part of a pipeline and are therefore run as a subshell, but it is because of the |, not the { ... }. You mention this in the question. AFAIK, you can do a return from within these inside a function.

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



Bash also provides the shoptbuiltin and one of its many options is:

Bash 还提供了shopt内置函数,其众多选项之一是:

lastpipe

If set, and job control is not active, the shell runs the last command of a pipeline not executed in the background in the current shell environment.

lastpipe

如果设置,并且作业控制未处于活动状态,shell 将运行当前 shell 环境中未在后台执行的管道的最后一个命令。

Thus, using something like this in a scriptmakes the modfied sumavailable after the loop:

因此,在脚本中使用类似的东西sum可以在循环后使用modfied :

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

Doing this at the command line usually runs foul of 'job control is not active' (that is, at the command line, job control is active). Testing this without using a script failed.

在命令行执行此操作通常会违反“作业控制未激活”(即,在命令行中,作业控制处于活动状态)。在不使用脚本的情况下测试失败。

Also, as noted by Gareth Reesin his answer, you can sometimes use a here string:

此外,正如Gareth Rees在他的回答中所指出的,您有时可以使用here 字符串

while read i; do echo $i; done <<< "$FILECONTENT"

This doesn't require shopt; you may be able to save a process using it.

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

回答by Gareth Rees

Jonathan Leffler explainshow to do what you want using process substitution, but another possibility is to use a here string:

Jonathan Leffler 解释了如何使用流程替换来做您想做的事情,但另一种可能性是使用here 字符串

while read i; do echo "$i"; done <<<"$FILECONTENT"

This saves a process.

这节省了一个过程。