问题描述
有人可以解释下面的代码如何工作吗?
echo '1 2 3 4 5 6' | while read a b c
do
echo $c $b $a
done
具体来说,我想知道为什么此循环的输出是3 4 5 6 2 1
,而不是在两行中的3 2 1
和6 5 4
?我似乎无法全神贯注于此…
最佳方法
read
从标准输入中读取整行,将行拆分为字段,并将此字段分配给给定变量。如果片段多于变量,则剩余片段将分配给最后一个变量。
在您的情况下,将$a
分配给1
,将$b
分配给2
,并且将$c
分配给其余的3 4 5 6
。
次佳方法
用这种方式重写循环可以揭示正在发生的事情:
echo '1 2 3 4 5 6' | while read a b c
do
echo '(iteration beginning)' a="$a" b="$b" c="$c" '(iteration ending)'
done
这给出了其输出:
(iteration beginning) a=1 b=2 c=3 4 5 6 (iteration ending)
首先请注意,仅运行一个echo命令。如果它多次运行,则除其他外,您还将看到多次打印的(iteration beginning)
和(iteration ending)
子字符串。
就是说,这里有一个while
循环并没有真正完成任何事情。内置的read
将whitespace-separated text1读取到每个指定的变量中。额外的输入将附加到指定的最后一个变量的末尾。2因此,变量a
和b
的值分别为1
和2
的值,而c
的值为3 4 5 6
。
第二次评估循环条件(while read a b c
)时,管道中不再有可用的输入(我们仅将其通过管道传输到一行文本中),因此read
命令的计算结果为false而不是true,并且循环停止(之前再次执行尸体)。
1:从技术和角度上讲,内置read
(在将变量名称作为参数传递时)在遇到IFS whitespace时读取输入splitting it into separate “words”(另请参见this question和this article)。
2:首先,read
会将输入的任何额外字段干扰到指定的最后一个变量中的行为对许多脚本编写者而言并不直观。当您考虑到as Florian Diesch’s answer says,read
将始终(尝试)读取整行并且read
既可以循环使用也可以不循环使用时,会更容易理解。