Bash while 循环意外停止
Bash while loop stops unexpectedly
我正在分析两个具有我不理解的行为的脚本:
#/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 循环是无限的。
有什么区别?我认为这是管道和支架的问题,但我无法解释。
问题是{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
)
这是一种更 'standard' 的方式。它还避免使用 pipe |,它强制 {read ..} 块作为单独的进程到 运行,然后使得无法观察 主 shell.
中读取命令的效果
而 <( .. ) 称为 进程替换 。它基本上执行包含的块,同时将其输出捕获到一个临时文件中,然后 returns 该临时文件名。
您在 pipe 之后使用 read
的循环在第一次迭代后终止,因为 SIGPIPE 信号的调用发生在 LHS pipe 写入一个管道,其输出未被读取,因为在 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 捕获所有数据。
我正在分析两个具有我不理解的行为的脚本:
#/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 循环是无限的。
有什么区别?我认为这是管道和支架的问题,但我无法解释。
问题是{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
)
这是一种更 'standard' 的方式。它还避免使用 pipe |,它强制 {read ..} 块作为单独的进程到 运行,然后使得无法观察 主 shell.
中读取命令的效果而 <( .. ) 称为 进程替换 。它基本上执行包含的块,同时将其输出捕获到一个临时文件中,然后 returns 该临时文件名。
您在 pipe 之后使用 read
的循环在第一次迭代后终止,因为 SIGPIPE 信号的调用发生在 LHS pipe 写入一个管道,其输出未被读取,因为在 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 捕获所有数据。