如何在循环结束后将输入传送到 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 < <(cat /etc/passwd); echo $i
时,它没有两次返回最后一行。我做错了什么?
@WakanTanka:我不得不尝试一下......我相信答案是失败的读取将i
重置为空,因此循环后的回显会回显一个空行。
对流程替换参考的赞誉。我不知道。
@Wakan Tanka:得到了和你一样的结果,我用 while read i; do x=$i; done < <(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 循环并保留变量的主要内容,如果未能解决你的问题,请参考以下文章