如何获得管道命令的pid?

时间:2014-05-12 18:40:57

标签: bash

(或如何杀死子进程)?

inotifywait -mqr --format '%w %f %e' $feedDir | while read dir file event
do
#something
done &

echo $! #5431

ps例如:

 >$ ps
  PID TTY          TIME CMD
 2867 pts/3    00:00:02 bash
 5430 pts/3    00:00:00 inotifywait
 5431 pts/3    00:00:00 bash
 5454 pts/3    00:00:00 ps

似乎我杀了 5431 然后 5430 inotifywait )将继续运行,但如果我杀了 5430 然后两个过程都死了。我不认为我可以可靠地假设 inotifywait 的pid总是比 $!小1?

2 个答案:

答案 0 :(得分:2)

当我们运行管道时,每个命令都在一个单独的进程中执行。解释器等待最后一个但是如果我们使用&符号(&)。

cmd1 | cmd2 &

流程的pid可能很接近,但我们不能可靠地假设它。在最后一个命令是bash保留字的情况下,它会创建一个专用的bash(这就是为什么你的'dir','file'变量在done关键字之后不存在)。例如:

ps # shows one bash process
echo "azerty" | while read line; do ps; done # shows one more bash

当第一个命令退出时,第二个命令将终止,因为管道上的读取返回EOF。 当第二个命令退出时,第一个命令将在尝试写入管道时由signal SIGPIPE(在没有读取器的管道上写入)终止。但是如果命令无限期地等待......它就不会被终止。

回声“$!”打印在后台执行的最后一个命令的pid。在您的情况下,正在执行while循环的bash进程。

您可以使用以下语法找到“inotifywait”的pid。但这很糟糕:

(inotifywait ... & echo "$!">inotifywait.pid) | \
while read dir file event
do
    #something
done &
cat inotifywait.pid # prints pid of inotifywait

如果您不想要pid,但只是确保该进程将被终止,您可以使用inotifywait的-t选项:

(while true; do inotifywait -t 10 ...; done)| \
while read dir file event
do
    #something
done &
kill "$!" # kill the while loop

这个解决方案都不好。你的真正成就是什么?也许我们可以找到更优雅的解决方案。

答案 1 :(得分:0)

如果你的目标是确保所有的孩子都能被优雅地杀死或打断。如果您使用的是BusyBox的Ash,则不需要进行流程替换。如果您不想使用fd,请查看此解决方案。

#!/bin/sh

pid=$$

terminate() {
  pkill -9 -P "$pid"
}

trap terminate SIGHUP SIGINT SIGQUIT SIGTERM

# do your stuff here, note: should be run in the background {{{
inotifywait -mqr --format '%w %f %e' $feedDir | while read dir file event
do
#something
done &
# }}}

# Either pkill -9 -P "$pid" here

wait

# or pkill -9 -P "$pid" here

或者在另一个shell中:

kill <pid ($$)>