PID为负表示这其实是PGID (Process Group ID),向这个PGID中的所有进程发信号。
例:向34325
进程组的所有进程发送SIGTERM
:
kill -TERM -34325
¶ 查看进程组的方法
ps -efj
。来源:PID,
PPID, PGID与SID
¶ 在一个新的进程组中运行命令
脚本里运行命令时,默认会继承当前进程组。但我们也可以让命令在一个新的进程组中执行。
¶ setsid
setsid command args...
如果是pipeline命令:
setsid sh -c "command1 | command2 | command3"
¶ bash:
set -m
对于bash
,如果要让命令在新的进程组中运行,可以在脚本中先开启"monitor mode" (job control)
:
set -m
局部生效:
(set -m; sleep 10)
来源:https://stackoverflow.com/questions/6549663/how-to-set-process-group-of-a-shell-script
在后台运行:
(set -m; sleep 10 &)
打印生成的后台进程的进程号:
(set -m; sleep 10 & echo $! )
注意&
本身已经表示了语句的结尾,所以&
后面如果再加;
的话bash
会报错:
$ (set -m; sleep 10 &; echo $! )
bash: syntax error near unexpected token `;'
不过zsh允许空语句;
,所以不会报错。
将生成的后台进程的进程号保存到变量:
pid=$(set -m; sleep 10 > /dev/null & echo $! )
echo $pid
command
substitution会等待所有stdout的writer关闭管道,因此要将sleep 10
的stdout重定向到/dev/null
。来源:https://stackoverflow.com/questions/51507719/why-is-this-command-substitution-waiting-for-the-background-job-to-finish
需要注意的是,如果命令需要读取管道,那么在管道被写之前,即使命令是后台命令,这个后台进程也不会被创建。例如:
mkfifo /tmp/pipe
pid=$(set -m; sleep 10 < /tmp/pipe > /dev/null & echo $!)
echo $pid
会卡死主shell。只有在另一个shell里往管道里写数据:echo test > /tmp/pipe
,sleep 10
的后台进程才会被创建,echo $pid
才会被执行。
同样,如果命令需要写管道,那么在管道被读之前,后台进程也不会被创建:
mkfifo /tmp/pipe
pid=$(set -m; sleep 10 > /tmp/pipe & echo $!)
echo $pid
只有在另一个shell读取管道:cat /tmp/pipe
,sleep 10
的后台进程才会被创建。
这可能跟管道的实现有关,只有当读写进程都就位之后进程才会被创建。
在同一个shell里创建读写进程,我们可以将创建进程的部分放入一个单独的进程里:
mkfifo /tmp/pipe
pid=$(set -m; (sleep 10 > /tmp/pipe) > /dev/null & echo $!)
echo $pid
pid=$(set -m; (sleep 10 < /tmp/pipe) > /dev/null & echo $!)
echo $pid