如何在循环结束后将输入传送到 Bash while 循环并保留变量

Posted

技术标签:

【中文标题】如何在循环结束后将输入传送到 Bash while 循环并保留变量【英文标题】:How to pipe input to a Bash while loop and preserve variables after loop ends 【发布时间】:2013-11-03 10:11:54 【问题描述】:

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 语句包含在 中,但这并不能解决问题(假设您想在函数中使用 while 循环并返回 i 变量)

【问题讨论】:

mywiki.wooledge.org/BashFAQ/024 相关:***.com/questions/37229058/…。解释所有选项,包括下面提到的进程替换和lastpipe 及其优缺点。 相关:A variable modified inside a while loop is not remembered. 【参考方案1】:

Process Substitution 的正确表示法是:

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

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

echo $FILECONTENT | 

while read i; do echo $i; done
...do other things using $i here...

大括号是 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

在命令行执行此操作通常会遇到“作业控制未激活”(即,在命令行,作业控制已激活)。在不使用脚本的情况下测试失败。

另外,正如Gareth Rees 在他的answer 中所指出的,您有时可以使用here string:

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

这不需要shopt;您也许可以使用它保存一个进程。

【讨论】:

原谅我的无知。我知道这是正确的解决方案,并且我已将其标记为答案,因此它对我有用。但是现在当我运行while read i; do echo $i; done &lt; &lt;(cat /etc/passwd); echo $i 时,它没有两次返回最后一行。我做错了什么? @WakanTanka:我不得不尝试一下......我相信答案是失败的读取将i 重置为空,因此循环后的回显会回显一个空行。 对流程替换参考的赞誉。我不知道。 @Wakan Tanka:得到了和你一样的结果,我用 while read i; do x=$i; done &lt; &lt;(cat /etc/passwd); echo i=$i; echo x=$x 工作,//也许那些日子 bash 行为改变了? 你是救生员!一直在寻找类似的解决方案。你是唯一有效的。【参考方案2】:

Jonathan Leffler explains 如何使用process substitution 做你想做的事,但另一种可能是使用here string

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

这节省了一个进程。

【讨论】:

【参考方案3】:

这个函数使 jpg 文件重复 $NUM 次(bash)

function makeDups() 
NUM=$1
echo "Making $1 duplicates for $(ls -1 *.jpg|wc -l) files"
ls -1 *.jpg|sort|while read f
do
  COUNT=0
  while [ "$COUNT" -le "$NUM" ]
  do
    cp $f $f//sm/$COUNTsm
    ((COUNT++))
  done
done

【讨论】:

以上是关于如何在循环结束后将输入传送到 Bash while 循环并保留变量的主要内容,如果未能解决你的问题,请参考以下文章

Bash:如何在按下任意键的情况下结束无限循环?

如何在 bash 中进行 while 循环工作?

Bash点点点

Bash编程 循环与分支

用户输入与while循环

如何使用定时全局变量影响 bash while 循环?