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

时间:2013-10-24 15:39:59

标签: bash while-loop stdin pipe

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变量)

3 个答案:

答案 0 :(得分:85)

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 Reesanswer所述,您有时可以使用here string

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

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

答案 1 :(得分:25)

Jonathan Leffler explains如何使用process substitution执行您想要的操作,但另一种可能性是使用here string

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

这可以节省一个过程。

答案 2 :(得分: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
}