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


87

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

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

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

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

我的问题是:

如何实现这样的目标:while read i; do echo $i; done <(echo "$FILECONTENT")换句话说:如何确定iwhile循环中是否还存在?

请注意,我知道将while语句包含在其中,{}但这不能解决问题(假设您要在函数中使用while循环并返回i变量)



相关:stackoverflow.com/questions/37229058/…。解释所有选项,包括以下提到的过程替换lastpipe及其优缺点。
ivan_pozdeev

Answers:


115

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

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分组操作,它们本身不会创建子外壳。在这种情况下,它们是管道的一部分,因此作为子外壳程序运行,但这是因为而|不是{ ... }。您在问题中提到了这一点。AFAIK,您可以在函数内部的这些函数中进行返回。


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

lastpipe

如果设置了该选项,并且作业控制未处于活动状态,则外壳程序会在当前外壳程序环境中运行不在后台执行的管道的最后一条命令。

因此,在脚本中使用类似这样的内容可使修改的内容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回答中指出的那样,有时您可以使用here字符串

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

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


原谅我的无知。我知道这是正确的解决方案,因此我已将其标记为答案,因此对我有用。但是现在当我运行时,while read i; do echo $i; done < <(cat /etc/passwd); echo $i它没有两次返回最后一行。我做错了什么?
Wakan Tanka'2

@WakanTanka:我不得不做一点实验...我相信答案是读取失败会重置i为空,因此循环后的回显会回显空白行。
Jonathan Leffler

1
供过程替代参考的荣誉。我没有意识到。
Atcold

@Wakan Tanka:得到了与您相同的结果,我使用了while read i; do x=$i; done < <(cat /etc/passwd); echo i=$i; echo x=$x工作原理,//也许那几天bash行为发生了变化?
yurenchen '18年

您是救生员!一直在寻找类似解决方案的时间。您的是唯一可行的。
专利


0

此功能使jpg文件(bash)重复$ NUM次

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/${COUNT}sm}
    ((COUNT++))
  done
done
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.