7.13. Использование контроля за задачами (job control)

Описание:  Кандидат должен знать как запустить процесс в фоновом режиме, переместить запущенный процесс в фон, вернуть на передний план процесс работающий в фоне. Кандидат должен уметь проверить запущены ли какие-нибуть задачи в фоновом режиме и знать разницу между командой kill(1) и встроенной в оболочку командой kill.

Практика: &, ^Z, jobs, fg, bg, и встроенная в оболочку kill.

Комментарий

Каждая команда (или, точнее, каждый конвейер, pipeline) в sh(1) должен заканчиваться либо знаком ;, либо &. В случае, если нет ни того ни другого, а в конце команды пользователь просто нажал на клавишу <Enter>, неявно подразумевается знак ;.

Конвейер заканчивающийся на ; выполняется «на переднем плане» (foreground). Оболочка не возвращает приглашения до тех пор, пока конвейер не отработает. Т.е. оболочка ждёт пока закончится процесс выполняющийся на переднем плане.

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

Список Конвейеров и их статус можно посмотреть при помощи встроенной в оболочку команды jobs. Эта команда перечисляет запущенные в фоновом режиме процессы и объясняет выполняются они или остановлены. В квадратных скобках jobs сообщает номер задания, следующее число — PID процесса. Если у задания стоит знак +, то это «текущее задание». С ним по умолчанию будут работать команды bg и fg.

Конвейер выполняющийся в фоновом режиме можно перевести на передний план при помощи команды fg [%n]. Необязательный аргумент — номер задания, его сообщяет команда jobs, если он не указан, на передний план будет переведено «текущее задание».

Чтобы перевести задание с переднего плана в фоновый режим, надо послать ему из оболочки сигнал SIGSTOP нажав сочетание клавиш <Ctrl>+Z. После этого оболочка вернёт приглашение, но процесс будет остановлен. Теперь надо послать процессу сигнал SIGCONT, для этого надо выполнить либо команду fg и вернуть его на передний план, либо bg и продолжить его в фоновом режиме. Мне приходилось наблюдать как люди запускают vi(1) (см. Раздел 7.3, «Навыки работы в vi(1)») и нажимат в нём <Ctrl>+Z пребывая в заблуждении, что так выходят из редактора. Спустя короткое время у них в оболочке накапливается большое количество остановленных vi(1).

Для того, чтобы послать запущенному заданию иной сигнал, служит встроенная команда kill. Она ведёт себя идентично внешней команде kill(1), но в отличие от последней, может послать сигнал заданию, не только по PID, но и по номеру, выдаваемому командой jobs. Для этого, номер надо предварить знаком %. Если скомандовать kill % без номера, будет уничтожено «текущее задание».

[Замечание]Замечание
Команда kill в sh(1) нереализована. Она есть только в csh(1) (и конечно в bash(1)). Остальные команды имеются в обоих интерпретаторах.

Ниже приведён пример на csh(1).

% sleep 1000 & sleep 2000 & sleep 3000 & 1
[1] 2028
[2] 2029
[3] 2030
% fg %2 2
sleep 2000
^Z 3
Suspended
% jobs
[1]  - Выполняется                   sleep 1000
[2]  + Suspended                     sleep 2000
[3]    Выполняется                   sleep 3000
% kill % 4
[2]    Прервано                      sleep 2000
% jobs
[1]  + Выполняется                   sleep 1000
[3]  - Выполняется                   sleep 3000
% fg %3 5
sleep 3000
^Z
Suspended
% bg 6
[3]    sleep 3000 &
% jobs
[1]  + Выполняется                   sleep 1000
[3]    Выполняется                   sleep 3000
% kill %3 7
[3]    Прервано                      sleep 3000
% kill -STOP % 8
[1]  + Suspended (signal)            sleep 1000
% kill -CONT %
[1]    sleep 1000 &
% jobs
[1]  + Выполняется                   sleep 1000
%
        

1 Запускаем сразу три задания, все три сразу в фоновом режиме.
2 Задание номер 2 выводим на передний план.
3 Сочетанием <Ctrl>+Z заставляем его «заснуть» и снова получаем приглашение командной строки. Фактически мы послали процессу сигнал SIGSTOP. Ниже, вывод команды jobs показывает, что второе задание остановлено.
4 Поскольку мы не указали команде kill номер задания, а указали просто знак процента, без числа, было прервано «текущее задание» т.е. то, у которого в выводе команды jobs стоял знак плюс.
5 Выводим на передний план и усыпляем третье задание.
6 Теперь можно командой bg продолжить выполнение усыплённого задания. Таким образом можно увести в фоновый режим любое задание выполняющееся на переднем плане: усыпить <Ctrl>+Z и продолжить bg.
7 Убиваем задание, но не «текущее», а по номеру (номер указываем в явном виде).
8 Команда kill может послать любой сигнал, в том числе сигнал SIGSTOP и SIGCONT. Приведённая команда эквивалентна сочетанию fg+<Ctrl>+Z. А следующая эквивалентна команде bg.

[Важно]Важно
Никогда не запускайте команду sudo(8) в фоновом режиме. Это типичная ошибка начинающего администратора: напустить команду вроде: sudo find /etc ... & Следующим номером программы утилита sudo(8) спрашивает у администратора пароль, он вводит его не гладя на экран и нажимает на <Enter>. Увы, пароль он вводит при этом не в программу sudo(8), а в оболочку (ведь sudo(8) запущена в фоне). После этого пароль в открытом виде не только отображается на экран, но так же сохраняется в разнообразных буферах и history-файлах. Лучше запустите программу sudo(8) на переднем плане, введите пароль, а потом переведите её в фоновый режим описанным выше способом (<Ctrl>+Z и bg).

Перечень сигналов, которые посылает команда kill, и их описание можно найти в man signal. С точки зрения администрирования продставляют интерес следующие сигналы:

Таблица 7.13. Некоторые сигналы, представляющие интерес для администратора

СигналНомерОписание
SIGHUP1 Посылается демонам для перечитывания ими конфигурационных файлов, а так же всем процессам-потомкам при уничтожении родителя. Если в терминале надо запустить программу, которая будет продолжаться и после закрытия терминала, её можно, как вариант, запустить внутри программы nohup(1), которая будет перехватывать данный сигнал. Команда nohup встроена в оболочку csh(1). Из sh(1) её можно вызвать как внешнюю программу.
SIGINT2Прерывание процесса. Этот сигнал посылается процессу, когда в оболочке пользователь нажимает клавишесочетание <Ctrl>+C
SIGKILL9 Уничтожение процесса. Этот сигнал неперехватывается приложением, больше того, оно даже ничего не узнаёт о том, что применён данный сигнал. Фактически это сигнал ядру о том, что данный процесс должен быть уничтожен.
SIGTERM15 Програмное завершение процесса. Приложение имеет возможность перехватить его и выполнить необходимые финализационные действия: стереть временные файлы, освободить иные ресурсы и т.п. Именно этот сигнал посылается приложению по умолчанию, когда команде kill не указано какой сигнал надо доставить процессу.
SIGSTOP  Остановить процесс (нельзя перехватить, направляется ядру). Этот сигнал посылается процессу, когда в оболочке пользователь нажимает клавишесочетание <Ctrl>+Z
SIGCONT  Продолжить остановленный процесс

Если сигнал направлен на PID равный -1, он доставляется всем процессам (если его вызвал суперпользователь) или всем процессам данного пользователя. В OpenBSD и NetBSD есть дополнительные псевдо-PID'ы 0 и -pgid, служащие для доставки сигнала группам процессов.