我正在分析两个脚本,其中包含一些我不理解的行为:
#/bin/bash
tijd=${1-60}
oud=`ls -l $MAIL`
while : ; do
nieuw=`ls -l $MAIL`
echo $oud $nieuw
sleep $tijd
done | { read a b rest ; echo $a ; echo $b ; echo $rest ; }
此脚本中的while循环在一次迭代后停止。
#/bin/bash
tijd=${1-60}
oud=`ls -l $MAIL`
while : ; do
nieuw=`ls -l $MAIL`
echo $oud $nieuw
sleep $tijd
done | cat
此脚本中的while循环是无限的。
有什么区别?我认为它与管道和括号有关,但我无法解释它。
答案 0 :(得分:3)
在管道之后read
的循环在第一次迭代后终止,因为调用 SIGPIPE 信号,管道的LHS写入管道输出为不读,因为RHS上的read
周围没有while循环。您cat
退出的示例不会退出,因为cat
连续从输入读取,其中read
终止后读取一行
要理解这种行为,首先要减少你的例子:
while : ; do pwd; done | { read -r line; echo $line; }
/Users/admin
所以read
在第一行后终止。要使用以下方式验证此操作pipefail
:
set -o pipefail
并检查退出状态:
while : ; do pwd; done | { read -r line; echo "$line"; }
echo $?
141
存在状态141
归因于SIGPIPE
。
要解决此问题,现在在while循环中更改管道RHS上的read
:
while : ; do pwd; sleep 5; done | { while read -r line; do echo "$line"; done; }
/Users/admin
/Users/admin
/Users/admin
现在你不会看到命令退出,因为while read
正在不断捕获管道LHS的所有数据。
答案 1 :(得分:0)
问题在于 {read a b rest; ..} 块仅执行一次,并且读取命令读取一行输入,而您希望它读取多行
你想写的是:
#/bin/bash
tijd=${1-60}
oud=`ls -l $MAIL`
while read a b rest; do
echo $a
echo $b
echo $rest
done < <(
while : ; do
nieuw=`ls -l $MAIL`
echo $oud $nieuw
sleep $tijd
done
)
这是一个更多的标准&#39;这样做的方式。它还避免使用管道,这会强制 {read ..} 块作为单独的进程运行,这样就无法观察主shell中read命令的效果。
&lt;(..)的事情称为流程替换。它基本上执行包含的块,同时将其输出捕获到临时文件中,然后返回该临时文件名。