如何设置一个shell脚本的进程组? 另外我希望所有的subprocess都在同一个进程组中
我期望在C中与setpgid()类似。
PSkocik指出 ,通过激活作业控制(“监视模式”),可以在大多数shell中在其自己的进程组中运行一个进程。
(set -m; exec process_in_its_own_group)
Linux有一个setsid
工具,它在自己的会话中使用作为参数传递的命令(使用同名的系统调用 )。 这比在它自己的setpgrp
过程组中运行它更强大,但是对于您的目的而言也许是可以的。
如果你想把进程放在一个现有的组中,而不是在它自己的组中(也就是说,如果你想要setpgid
的全部功能),那么就没有常用的shell工具。 你必须使用C / Perl / …
我不认为Bourne,bash或者zsh会让你这样做,但是你可以在perl中使用内置的setpgrp
(注意与POSIX略有不同)。 传递零作为PID来修改perl进程本身的组:
setpgrp(0, 12345) || die "$!"
你可能会认为你可以用bash来设置bash进程的组(例如,通过将$$
传递给perl脚本),但是我不认为perl进程能够修改过程,它没有分叉。
根据你想要做的事情,各种shell中的作业控制功能可能会以不同的方式给你所需要的东西,比如你只是想从终端上分离出来。
更新:我觉得奇怪的是,这个答案已经收到了一些没有明确解释为什么的票。 我的猜测是,downvoters误解了这个问题,就是如何改变 当前 shell的进程组。 或者也许他们知道如何从shell中执行setpgrp,但保留自己的秘密。
我会回答我所理解的部分内容:
如何强制当前的bash shell脚本是它自己的进程组:
我把这个放在我的bash脚本的开头:
pgid_from_pid() { local pid=$1 ps -o pgid= "$pid" 2>/dev/null | egrep -o "[0-9]+" } pid="$$" if [ "$pid" != "$(pgid_from_pid $pid)" ]; then exec setsid "$(readlink -f "$0")" "$@" fi
为什么我需要这个?
从交互式 bash会话启动程序时,它将获得自己的新进程组。 但是,如果您的程序是从bash脚本(非交互式)调用的,则不是这种情况。 如果你的程序依赖于在这两种情况下的过程组所有者,你将需要这个。
如果将set -m
on,则将在新的进程组中生成新进程,如果它们是后台进程,则不会忽略SIGINT和SIGQUIT。
if [ $$ = $(ps -o pgid -hp $$) ]; then echo already a process group leader; else set -m $0 "$@" #optionally with & set +m fi
set -m
之后运行的程序的新进程组将作为终端的前台进程组接管,除非它们在后台运行。
如果实现支持“用户可移植性实用程序”, set -m
显然是半标准的,POSIX要求。 在实践中,它在bash
, dash
, ksh
, pdksh
, sh
, yash
和zsh
。 posh
没有它。
正如@Rob Davis在他的回答中指出的,设置进程组并不是你想要的shell。
相反,你想使用他们的过程控制机制。 这个答案涵盖了在Linux上执行此操作,并承担 。 简而言之:
#! /bin/sh # Kill all opened jobs on exit. trap 'kill $(jobs -p)' EXIT
这将杀死任何在backrground中打开的作业(例如用&
)。