如何获取管道命令的进程ID(PID)?

7
(或如何终止子进程)?
inotifywait -mqr --format '%w %f %e' $feedDir | while read dir file event
do
#something
done &

echo $! #5431

例子:

 >$ 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,那么inotifywait5430将继续运行,但如果我杀死5430,那么这两个进程都会死亡。我不能可靠地假设inotifywait的pid始终比$!少1个吗?


你确定 $$ 是 5431 吗?我认为 5431 是你将 inotify 管道传递到的 while - Jan Matějka
我肯定期望$$比inotifywait的pid要低,除非pid号码已经循环了,那么它们彼此相邻的机会(±1)就非常小了。 - Jan Matějka
1
哦,"手动地"?按照代码示例中的样子在脚本中运行它。 - Jan Matějka
1
这个有帮助吗?https://dev59.com/d3I-5IYBdhLWcg3w1sPi - Jan Matějka
2
如果你真的必须找到PID,你可以通过使用命名管道将两个命令分离来实现。你可以使用mknodmkfifo创建一个命名管道,方法是:command1 > PIPE &; pid1=$PID; command2 < PIPE。有关命名管道的更多信息,请参见http://www.linuxjournal.com/content/using-named-pipes-fifos-bash。 - haridsv
显示剩余7条评论
2个回答

3
当我们运行一个管道时,每个命令都在单独的进程中执行。如果使用&符号,则解释器会等待最后一个命令的完成。
cmd1 | cmd2 &

进程的pid可能会很接近,但我们不能可靠地假设。如果最后一个命令是bash保留字(如while),它将创建一个专用的bash(这就是为什么在done关键字之后你的“dir”、“file”变量不会存在的原因)。例如:
ps # shows one bash process
echo "azerty" | while read line; do ps; done # shows one more bash

当第一个命令退出时,第二个命令将终止,因为管道上的读取返回EOF。 当第二个命令退出时,第一个命令将被信号SIGPIPE(在没有读取器的管道上写入)终止,当它尝试写入管道时。但是,如果命令无限期地等待...它不会被终止。
echo“$!”打印在后台执行while循环的bash进程的pid。
您可以使用以下语法查找“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
如果你的目标是确保所有的子进程可以被优雅地杀死或中断,如果你使用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 ($$)>

1
trap terminate SIGHUP SIGINT SIGQUIT SIGTERM 怎么样?(除非你凭行数收费...) - David C. Rankin
我不知道我可以这样做。谢谢! - Johann Chang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接