如何管道输入到 Bash while 循环,并保留循环结束后的变量

允许使用的 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变量)

120333 次浏览

The correct notation for Process Substitution is:

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

The last value of i assigned in the loop is then available when the loop terminates. An alternative is:

echo $FILECONTENT |
{
while read i; do echo $i; done
...do other things using $i here...
}

The braces are an I/O grouping operation and do not themselves create a subshell. In this context, they are part of a pipeline and are therefore run as a subshell, but it is because of the |, not the { ... }. You mention this in the question. AFAIK, you can do a return from within these inside a function.


Bash also provides the shopt builtin and one of its many options is:

lastpipe

If set, and job control is not active, the shell runs the last command of a pipeline not executed in the background in the current shell environment.

Thus, using something like this in a script makes the modfied sum available after the loop:

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

Doing this at the command line usually runs foul of 'job control is not active' (that is, at the command line, job control is active). Testing this without using a script failed.

Also, as noted by Gareth Rees in his answer, you can sometimes use a here string:

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

This doesn't require shopt; you may be able to save a process using it.

Jonathan Leffler explains how to do what you want using process substitution, but another possibility is to use a here string:

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

This saves a process.

This function makes duplicates $NUM times of jpg files (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
}