管道导向while循环

请使用过程替换或者 for 循环,而不是管道导向 while 循环。在 while 循环中被修改的变量是不能传递给父 shell 的,因为循环命令是在一个子 shell 中运行的。 管道导向 while 循环中的隐式子 shell 使得追踪 bug 变得很困难。

last_line='NULL'
your_command | while read line; do
last_line="${line}"
done

# This will output 'NULL'

echo "${last_line}"

如果你确定输入中不包含空格或者特殊符号(通常意味着不是用户输入的),那么可以使用一个 for 循环。


total=0

# Only do this if there are no spaces in return values.

for value in $(command); do
  total+="${value}"
done

使用过程替换允许重定向输出,但是请将命令放入一个显式的子 shell 中,而不是 bash 为 while 循环创建的隐式子 shell。

total=0
last_file=
while read count filename; do
total+="${count}"
  last_file="${filename}"
done < <(your_command | uniq -c)

# This will output the second field of the last line of output from

# the command.

echo "Total = ${total}"
echo "Last one = ${last_file}"

当不需要传递复杂的结果给父 shell 时可以使用 while 循环。这通常需要一些更复杂的“解析”。请注意简单的例子使用如 awk 这类工具可能更容易完成。当你特别不希望改变父 shell 的范围变量时这可能也是有用的。

# Trivial implementation of awk expression:
#   awk '$3 == "nfs" { print $2 " maps to " $1 }' /proc/mounts
cat /proc/mounts | while read src dest type opts rest; do
  if [[ ${type} == "nfs" ]]; then
    echo "NFS ${dest} maps to ${src}"
  fi
done