在bash中退出管道
对于以下bash语句:在bash中退出管道,bash,shell,pipe,quit,Bash,Shell,Pipe,Quit,对于以下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 -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”退出
你说得对。
while
循环在子shell中执行,因为它的输入被重定向,exit
只是从该子shell退出
如果您运行的是bash4.x
,则可以通过协进程实现所需的功能
coproc TAIL { tail -Fn0 /tmp/report.txt ;}
while [ 1 ]
do
echo "pre"
break
echo "past"
done <&${TAIL[0]}
kill $TAIL_PID
coproc TAIL{TAIL-Fn0/tmp/report.txt;}
而[1]
做
回音“pre”
打破
呼应“过去”
完成$pipe&
TAIL_PID=$!
而[1]
做
回音“pre”
打破
呼应“过去”
完成您可以(不可靠地)杀死进程组:
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]
的风格很差。(其行为与[0]
时的行为完全相同)。感谢您的帮助!现在我的知识在增长。我的bash是3.2.5。也许你的是最好的,而我仍在期待其他一些。你可以使用后台进程向命名管道写入来模拟协进程。添加了使用命名管道的解决方案。当读取器关闭某个管道时,该管道的编写器会出错。如果在循环内执行重定向,则每次通过循环都会打开和关闭它,第一次关闭会杀死写入程序。在第二个版本中,管道的读取端在整个循环中打开一次,只有在循环完成时才关闭。在我测试的情况下,集合-m可能重复,尽管背景与否似乎相同,但在这两种情况下,尾和尾都在同一个新流程组中。您能解释一下关于后台的更多信息吗?如果启用了作业控制,标准要求后台管道作为单独的进程组运行。尽管shell可以将前台组作为不同的进程组运行,但它不是必需的。
#!/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