我正在学习流程组,这对我来说是一个新事物。 (我尝试遵循这个答案,除其他外:为什么 SIGINT 发送到其父进程时没有传播到子进程?)。我尝试但无法终止进程组,因为它的 ID 似乎正在消失。
$ sleep 1000 &
[1] 6468
$ ps ax -O tpgid | grep sleep
6468 6511 S pts/4 00:00:00 sleep 1000
6512 6511 S pts/4 00:00:00 grep --color=auto sleep
$ kill -9 -6511
bash: kill: (-6511) - No such process
$ ps ax -O tpgid | grep sleep
6468 6515 S pts/4 00:00:00 sleep 1000
6516 6515 S pts/4 00:00:00 grep --color=auto sleep
$ ps ax -O tpgid | grep sleep
6468 6517 S pts/4 00:00:00 sleep 1000
6518 6517 S pts/4 00:00:00 grep --color=auto sleep
为什么会这样,怎样才能抓住并杀死它呢?我得到了什么以及做错了什么?
GNU bash,版本 4.3.42(1)-release (x86_64-pc-linux-gnu)
答案1
这是因为您没有打印进程组 ID (PGID),而是打印“控制 tty 进程组 ID”tpgid。正如中所解释的man ps
:
tpgid TPGID ID of the foreground process group on the tty
(terminal) that the process is connected to, or
-1 if the process is not connected to a tty.
因此,您看到的是前台进程的 PID,在您的情况下,它是程序ps
:
$ sleep 1000 &
[1] 6745
$ ps ax -O tpgid | grep -E 'sleep|ps a'
6745 7136 S pts/1 00:00:00 sleep 1000
7136 7136 R pts/1 00:00:00 ps ax -O tpgid
7137 7136 S pts/1 00:00:00 grep --color -E sleep|ps a
如上所示,打印的 tpgid 值是进程的 PID ps
。您正在寻找的是pgid
,而不是tpgid
:
pgid PGID process group ID or, equivalently, the process ID
of the process group leader. (alias pgrp).
$ ps ax -O pgid | grep -E 'sleep|ps a'
8414 8414 S pts/1 00:00:00 sleep 1000
8656 8656 R pts/1 00:00:00 ps ax -O pgid
8657 8656 S pts/1 00:00:00 grep --color -E sleep|ps a
当然,由于您实际上并未运行任何进程组(例如,当一个脚本调用其他脚本时会发生这种情况),因此 PGIDsleep
与其 PID 相同。不过,如果你愿意的话,你实际上可以这样杀死它:
$ kill -9 -8414
$ ps ax -O pgid | grep -E 'sleep|ps a'
10065 10065 R pts/1 00:00:00 ps ax -O pgid
10066 10065 S pts/1 00:00:00 grep --color -E sleep|ps a
[1]+ Killed sleep 1000
一个更具信息性的示例是运行如下脚本:
#!/bin/bash
sleep 1000 &
sleep 1000 &
sleep 1000 &
sleep 1000
如果我将其另存为foo.sh
并运行它,则各种sleep
命令都将具有相同的 PGID:
$ foo.sh &
[1] 13555
$ ps ax -O pgid | grep -P '[s]leep|[f]oo.sh'
13555 13555 S pts/1 00:00:00 /bin/bash /home/terdon/scripts/foo.sh
13556 13555 S pts/1 00:00:00 sleep 1000
13557 13555 S pts/1 00:00:00 sleep 1000
13558 13555 S pts/1 00:00:00 sleep 1000
13559 13555 S pts/1 00:00:00 sleep 1000
因此,每个子进程都位于父进程的进程组中foo.sh
。如果我们现在杀死进程组,所有进程都将退出:
$ kill -9 -13555
$ ps ax -O pgid | grep -P '[s]leep|[f]oo.sh'
[1]+ Killed foo.sh