对于以下bash语句:
tail -Fn0 /tmp/report | while [ 1 ]; do echo "pre"; exit; echo "past"; done
我得到了“pre”,但没有退出bash提示符,然后如果我在/ tmp / report中输入内容,我可以退出这个脚本并进入bash提示符。
我认为这是合理的。 'exit'使'while'语句退出,但'tail'仍然活着。如果输入/tmp/report
的内容,'tail'将输出到管道,那么'tail'将检测到管道已关闭,然后'tail'退出。
答案 0 :(得分:3)
你是对的。 while
循环正在子shell中执行,因为它的输入被重定向,而exit
只是退出该子shell。
如果您正在运行bash 4.x
,您可以通过协处理实现您想要的效果。
coproc TAIL { tail -Fn0 /tmp/report.txt ;}
while [ 1 ]
do
echo "pre"
break
echo "past"
done <&${TAIL[0]}
kill $TAIL_PID
http://www.gnu.org/software/bash/manual/html_node/Coprocesses.html
对于旧版本,您可以使用后台进程写入命名管道:
pipe=/tmp/tail.$$
mkfifo $pipe
tail -Fn0 /tmp/report.txt >$pipe &
TAIL_PID=$!
while [ 1 ]
do
echo "pre"
break
echo "past"
done <$pipe
kill $TAIL_PID
rm $pipe
答案 1 :(得分:1)
你可以(不可靠)逃脱杀死进程组:
tail -Fn0 /tmp/report | while :
do
echo "pre"
sh -c 'PGID=$( ps -o pgid= $$ | tr -d \ ); kill -TERM -$PGID'
echo "past"
done
这可能会将信号发送到比您想要的更多进程。如果在交互式终端中运行上述命令,您应该没问题,但在脚本中,完全有可能(实际上可能)进程组将包含运行该命令的脚本。为避免发送信号,最好在后台启用监控并运行管道,以确保为管道形成新的流程组:
#!/bin/sh
# In Posix shells that support the User Portability Utilities option
# this includes bash & ksh), executing "set -m" turns on job control.
# Background processes run in a separate process group. If the shell
# is interactive, a line containing their exit status is printed to
# stderr upon their completion.
set -m
tail -Fn0 /tmp/report | while :
do
echo "pre"
sh -c 'PGID=$( ps -o pgid= $$ | tr -d \ ); kill -TERM -$PGID'
echo "past"
done &
wait
请注意,我已将while [ 1 ]
替换为while :
,因为while [ 1 ]
风格较差。 (它的行为与while [ 0 ]
完全相同)。