95

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")或者换句话说:我如何确定在iwhile循环中存活?

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

4

3 回答 3

132

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

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。在这种情况下,它们是管道的一部分,因此作为子外壳运行,但这是因为 . 而|不是{ ... }. 你在问题中提到了这一点。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在他的回答中所指出的,您有时可以使用此处的字符串

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

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

于 2013-10-24T16:07:55.387 回答
29

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

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

这节省了一个过程。

于 2013-10-24T16:14:54.900 回答
1

此功能使 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/${COUNT}sm}
    ((COUNT++))
  done
done
}
于 2020-08-02T02:24:18.167 回答