Как установить группу процессов сценария оболочки - PullRequest
29 голосов
/ 01 июля 2011

Как установить группу процессов скрипта оболочки? Также я хочу, чтобы все дочерние процессы были в одной группе процессов

Я ожидаю что-то похожее на setpgid () в C.

Ответы [ 6 ]

18 голосов
/ 01 июля 2011

Как указывает PSkocik , можно запустить процесс в своей собственной группе процессов, в большинстве оболочек, активировав управление заданиями («режим мониторинга»).

(set -m; exec process_in_its_own_group)

В Linux есть утилита setsid, которая запускает команду, переданную в качестве аргумента, в своей собственной сессии (с использованием одноименного системного вызова ).Это сильнее, чем запускать его в собственной группе процессов а-ля setpgrp, но это может быть вполне приемлемым для вашей цели.

Если вы хотите разместитьпроцесс в существующей группе, а не в своей собственной группе (то есть, если вы хотите использовать все возможности setpgid), не имеет общей утилиты оболочки.Вы должны использовать C / Perl /…

10 голосов
/ 24 апреля 2016

Я отвечу на часть того, что я понимаю:

Как заставить текущий сценарий оболочки bash быть самостоятельной группой обработки:

Я поместил это вначало моего сценария 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-скрипта (не интерактивного).Если ваша программа полагается на то, чтобы быть владельцем группы процессов в обоих условиях, вам понадобится это.

9 голосов
/ 01 июля 2011

Я не думаю, что Bourne, bash или zsh позволят вам это сделать, но вы можете сделать это в perl, используя встроенный setpgrp (обратите внимание на небольшое отличие имени от POSIX).Передайте ноль в качестве PID для изменения группы самого процесса perl:

setpgrp(0, 12345) || die "$!"

Вы можете подумать, что вы можете использовать perl из, скажем, bash, чтобы установить группу процесса bash (передав $$ всценарий perl, например), но я не думаю, что процесс perl сможет изменить группу процесса, который он не обработал.

В зависимости от того, что вы пытаетесь сделать,Функции управления заданиями в различных оболочках могут дать вам то, что вам нужно, по-разному, например, если вы просто хотите отсоединиться от терминала.

ОБНОВЛЕНИЕ: Мне кажется странным, что этот ответполучил пару отрицательных голосов без четкого объяснения почему.Я предполагаю, что downvoters неправильно понимают вопрос, который спрашивает, как изменить группу процессов current shell.Или, может быть, они знают, как сделать setpgrp из оболочки, но держат секрет при себе.

4 голосов
/ 15 июля 2017

Если вы включите set -m, новые процессы будут порождаться в новой группе процессов, и если они будут фоновыми, у них не будут игнорироваться 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 не имеет его.

1 голос
/ 01 сентября 2018

Вот поздний синтез, взятый из нескольких других хороших ответов здесь, если вы намереваетесь очистить любые порожденные процессы подоболочки (даже если сам скрипт запускается не напрямую из интерактивной оболочки, а из другого процесса и поэтому не ' t автоматически становится собственным лидером группы процессов ), при необходимости перезапуская текущий скрипт как новый лидер группы процессов.

# First, obtain the current PGID, by parsing the output of "ps".
pgid=$(($(ps -o pgid= -p "$$")))

# Check if we're already the process group leader; if not, re-launch ourselves.
# Use setsid instead of set -m (...) to avoid having another subshell in between. This helps that the trap gets executed when the script is killed.
[ $$ -eq $pgid ] || exec setsid "${BASH_SOURCE[0]}" "$@"

# Kill any subshell processes when the script exits.
trap "kill -- -$pgid" EXIT
# Note: If the script only starts background jobs, and that's all you care about, you can replace all of the above with this simple trap:
#trap "jobs -p | xargs kill --" EXIT  # Kill remaining jobs when the script exits.
1 голос
/ 19 марта 2016

Как @Rob Davis указал в своем ответе , настройка группы процессов - это не то, что вам нужно для оболочек.

Вместо этого вы хотите использовать их механизмы управления процессами. Этот ответ охватывает выполнение этого для sh на linux и переносится .Вкратце:

#! /bin/sh
# Kill all opened jobs on exit.
trap 'kill $(jobs -p)' EXIT

Это убьет все задания, открытые в фоновом режиме (например, с &).

...