Как использовать Bash Job Control для управления передним и фоновым процессами

Вступление

В этом руководстве мы поговорим о том, какbash, система Linux и ваш терминал объединяются, чтобы обеспечить управление процессами и заданиями. Вprevious guide мы обсудили, как командыps,kill иnice могут использоваться для управления процессами в вашей системе.

Эта статья будет сосредоточена на управлении передним и фоновым процессами и продемонстрирует, как использовать функции управления заданиями вашей оболочки для повышения гибкости при выполнении команд.

Управление процессами переднего плана

Большинство процессов, которые вы запускаете на компьютере с Linux, будут выполняться на переднем плане. Команда начнет выполнение, блокируя использование оболочки на время процесса. Процесс может разрешить взаимодействие с пользователем или может просто пройти через процедуру и затем завершиться. Любой вывод будет отображаться в окне терминала по умолчанию. Ниже мы обсудим основной способ управления приоритетными процессами.

Запуск процесса

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

Некоторые команды переднего плана завершаются очень быстро и почти сразу возвращают вас в приглашение оболочки. Например, эта команда:

echo "Hello World"

Это выведет «Hello World» в терминал, а затем вернет вас в командную строку.

Другие команды переднего плана выполняются дольше, блокируя доступ к оболочке на время. Это может быть связано с тем, что команда выполняет более сложную операцию, или потому что она настроена на выполнение до тех пор, пока она не будет явно остановлена ​​или пока она не получит другой пользовательский ввод.

Команда, которая выполняется бесконечно, - это утилитаtop. После запуска он продолжит работу и обновит свой дисплей, пока пользователь не завершит процесс:

top

Вы можете выйти, набрав «q». Некоторые процессы не имеют специальной функции выхода. Чтобы остановить это, вам придется использовать другой метод.

Завершение процесса

Предположим, мы запускаем простой циклbash в командной строке. Мы можем запустить цикл, который будет печатать «Hello World» каждые десять секунд. Этот цикл будет продолжаться вечно, пока не будет явно завершен:

while true; do echo "Hello World"; sleep 10; done

Циклы не имеют клавиши «выход». Нам придется остановить процесс, отправив емуsignal. В Linux ядро ​​может отправлять сигналы процессов, чтобы запросить их выход или изменение состояний. Терминалы Linux обычно настроены на отправку сигнала «SIGINT» (обычно сигнал номер 2) текущему процессу переднего плана при нажатии комбинации клавишCTRL-C. Сигнал SIGINT сообщает программе, что пользователь запросил завершение с помощью клавиатуры.

Чтобы остановить начатый цикл, удерживайте клавишу управления и нажмите клавишу «c»:

CTRL-C

Цикл выйдет, вернув управление оболочке.

Сигнал SIGINT, отправляемый комбинациейCTRL-C, является одним из многих сигналов, которые могут быть отправлены программам. Большинство сигналов не имеют связанных с ними клавиатурных комбинаций и должны отправляться с помощью командыkill (мы рассмотрим это позже).

Приостановка процессов

Мы упоминали выше, что приоритетный процесс будет блокировать доступ к оболочке на время их выполнения. Что если мы запустим процесс на переднем плане, но затем поймем, что нам нужен доступ к терминалу?

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

В качестве демонстрации давайте будем использоватьping для подключения к google.com каждые 5 секунд. Перед командойping мы будем указыватьcommand, что позволит нам обойти любые псевдонимы оболочки, которые искусственно устанавливают максимальное количество для команды:

command ping -i 5 google.com

Вместо того, чтобы завершать команду с помощьюCTRL-C, введитеCTRL-Z:

CTRL-Z

Вы увидите вывод, который выглядит следующим образом:

Output[1]+  Stopped                 ping -i 5 google.com

Командаping временно остановлена, и вы снова получите доступ к приглашению оболочки. Мы можем использовать инструмент процессаps, чтобы показать это:

ps T
Output  PID TTY      STAT   TIME COMMAND
26904 pts/3    Ss     0:00 /bin/bash
29633 pts/3    T      0:00 ping -i 5 google.com
29643 pts/3    R+     0:00 ps t

Мы видим, что процессping все еще указан, но в столбце «STAT» есть буква «T». Страница руководстваps сообщает нам, что это задание, которое было «остановлено (a) сигналом управления заданием».

Мы обсудим более подробно, как изменить состояния процесса, но сейчас мы можем возобновить выполнение команды на переднем плане, набрав:

fg

Как только процесс возобновится, остановите его с помощьюCTRL-C:

CTRL-C

Управление фоновыми процессами

Основной альтернативой запуску процесса на переднем плане является разрешение его выполнения в фоновом режиме. Фоновый процесс связан с конкретным терминалом, который его запустил, но не блокирует доступ к оболочке. Вместо этого он выполняется в фоновом режиме, предоставляя пользователю возможность взаимодействовать с системой во время выполнения команды.

Из-за того, как процессы переднего плана взаимодействуют с его терминалом, для каждого окна терминала может быть только один процесс переднего плана. Поскольку фоновые процессы немедленно возвращают управление оболочке, не дожидаясь завершения процесса, многие фоновые процессы могут выполняться одновременно.

Стартовые процессы

Вы можете запустить фоновый процесс, добавив символ амперсанда («&») в конец ваших команд. Это говорит оболочке не ждать завершения процесса, а начинать выполнение и немедленно возвращать пользователя к приглашению. Вывод команды будет по-прежнему отображаться в терминале (кромеredirected), но вы можете вводить дополнительные команды по мере продолжения фонового процесса.

Например, мы можем запустить тот же процесс проверки связи из последнего раздела в фоновом режиме, набрав:

command ping -i 5 google.com &

Вы увидите вывод системы управления заданиямиbash, который выглядит следующим образом:

Output[1] 4287

Вы также увидите нормальный вывод командыping:

OutputPING google.com (74.125.226.71) 56(84) bytes of data.
64 bytes from lga15s44-in-f7.1e100.net (74.125.226.71): icmp_seq=1 ttl=55 time=12.3 ms
64 bytes from lga15s44-in-f7.1e100.net (74.125.226.71): icmp_seq=2 ttl=55 time=11.1 ms
64 bytes from lga15s44-in-f7.1e100.net (74.125.226.71): icmp_seq=3 ttl=55 time=9.98 ms

Однако вы также можете вводить команды одновременно. Вывод фонового процесса будет смешан между вводом и выводом ваших процессов переднего плана, но он не будет мешать выполнению процессов переднего плана.

Листинг фоновых процессов

Чтобы увидеть все остановленные или фоновые процессы, вы можете использовать командуjobs:

jobs

Если у вас запущена командаping в фоновом режиме, вы увидите примерно следующее:

Output[1]+  Running                 command ping -i 5 google.com &

Это показывает, что в настоящее время у нас запущен один фоновый процесс. [1] представляет собой «спецификацию задания» или номер задания. Мы можем ссылаться на это с другими командами управления заданиями и процессами, такими какkill,fg иbg, поставив перед номером задания знак процента. В этом случае мы будем ссылаться на это задание как на%1.

Остановка фоновых процессов

Мы можем остановить текущий фоновый процесс несколькими способами. Самый простой способ - использовать командуkill с соответствующим номером задания. Например, мы можем убить наш запущенный фоновый процесс, набрав:

kill %1

В зависимости от того, как настроен ваш терминал, сразу или в следующий раз, когда вы нажмете ENTER, вы увидите статус завершения задания:

Output[1]+  Terminated              command ping -i 5 google.com

Если мы снова проверим командуjobs, мы не увидим текущих заданий.

Изменение состояний процесса

Теперь, когда мы знаем, как запускать и останавливать процессы в фоновом режиме, мы можем поговорить о том, как изменить их состояние.

Мы продемонстрировали одно изменение состояния ранее, когда описывали, как остановить или приостановить процесс с помощьюCTRL-Z. Когда процессы находятся в этом остановленном состоянии, мы можем переместить процесс переднего плана в фоновый режим или наоборот.

Перемещение процессов переднего плана на задний план

Если мы забудем завершить команду с помощью& при ее запуске, мы все равно можем переместить процесс в фоновый режим.

Первый шаг - снова остановить процесс с помощьюCTRL-Z:

CTRL-Z

После остановки процесса мы можем использовать командуbg, чтобы снова запустить его в фоновом режиме:

bg

Вы снова увидите строку состояния задания, на этот раз с добавленным амперсандом:

Output[1]+ ping -i 5 google.com &

По умолчанию командаbg работает с последним остановленным процессом. Если вы остановили несколько процессов подряд, не запустив их снова, вы можете сослаться на процесс по номеру задания, чтобы установить правильный процесс.

Обратите внимание, что не все команды могут быть фоновыми. Некоторые процессы будут автоматически завершены, если обнаружат, что они были запущены со стандартным входом и выходом, напрямую подключенным к активному терминалу.

Перемещение фоновых процессов на передний план

Мы также можем переместить фоновые процессы на передний план, набравfg:

fg

Это работает с вашим последним фоновым процессом (обозначенным знаком «» в выводе «+ jobs»). Это немедленно приостанавливает процесс и выводит его на первый план. Чтобы указать другое задание, используйте его номер задания:

fg %2

Когда задание находится на переднем плане, вы можете убить его с помощьюCTRL-C, дать ему завершиться или приостановить и снова запустить его в фоновом режиме.

Работа с SIGHUP

Находится ли процесс в фоновом режиме или на переднем плане, он довольно тесно связан с экземпляром терминала, который его запустил. Когда терминал закрывается, он обычно отправляет сигнал SIGHUP всем процессам (передний план, фон или остановлен), которые связаны с терминалом. Это сигнализирует о прекращении процессов, потому что их управляющий терминал вскоре будет недоступен. Что, если вы хотите закрыть терминал, но фоновые процессы работают?

Есть несколько способов сделать это. Наиболее гибкими способами обычно являются использование терминального мультиплексора, такого какscreen илиtmux, или использование служебной программы, которая предоставляет, по крайней мере, их функцию отсоединения, напримерdtach.

Тем не менее, это не всегда вариант. Иногда эти программы недоступны, или вы уже запустили процесс, который вам нужен для продолжения работы. Иногда это излишне для того, что вам нужно сделать.

Используя nohup

Если при запуске процесса вы знаете, что хотите закрыть терминал до завершения процесса, вы можете запустить его с помощью командыnohup. Это делает запущенный процесс невосприимчивым к сигналу SIGHUP. Он продолжит работать, когда терминал закроется. Он будет переназначен как дочерний элемент системы init:

nohup ping -i 5 google.com &

Вы увидите строку, которая выглядит следующим образом, указывая, что вывод команды будет записан в файл с именемnohup.out (в текущем каталоге, если он доступен для записи, иначе в ваш домашний каталог):

Outputnohup: ignoring input and appending output to ‘nohup.out’

Это делается для того, чтобы вывод не терялся, если окно терминала закрыто.

Если вы закроете окно терминала и откроете еще одно, процесс все равно будет запущен. Вы не увидите его в выводе командыjobs, потому что каждый экземпляр терминала поддерживает свою собственную независимую очередь заданий. Закрытие терминала привело к уничтожениюpingjob, хотяpingprocess все еще работает.

Чтобы убить процессping, вам нужно найти его идентификатор процесса (или «PID»). Вы можете сделать это с помощью командыpgrep (есть также командаpkill, но этот двухкомпонентный метод гарантирует, что мы убиваем только предполагаемый процесс). Используйтеpgrep и флаг-a для поиска исполняемого файла:

pgrep -a ping
Output7360 ping -i 5 google.com

Затем вы можете завершить процесс, ссылаясь на возвращенный PID, который является номером в первом столбце:

kill 7360

Вы можете удалить файлnohup.out, если он вам больше не нужен.

Использование отречься

Командаnohup полезна, но только в том случае, если вы знаете, что она вам понадобится в момент запуска процесса. Система управления заданиямиbash предоставляет другие методы достижения аналогичных результатов с помощью встроенной командыdisown.

Командаdisown в своей конфигурации по умолчанию удаляет задание из очереди заданий терминала. Это означает, что им больше нельзя управлять с помощью механизмов управления заданиями, обсуждаемых в этом руководстве (например,fg,bg,CTRL-Z,CTRL-C). Он будет немедленно удален из списка в выводеjobs и больше не будет связан с терминалом.

Команда вызывается указанием номера задания. Например, чтобы немедленно отказаться от задания 2, мы могли бы набрать:

disown %2

Это оставляет процесс в состоянии, похожем на состояние процессаnohup после закрытия управляющего терминала. Исключением является то, что любой вывод будет потерян, когда управляющий терминал закроется, если он не будет перенаправлен в файл.

Обычно вы не хотите полностью удалять процесс из-под контроля задания, если не закрываете окно терминала сразу. Вместо этого вы можете передать флаг-h процессуdisown, чтобы пометить процесс игнорировать сигналы SIGHUP, но в противном случае продолжить работу как обычное задание:

disown -h %1

В этом состоянии вы можете использовать обычные механизмы управления заданиями, чтобы продолжать контролировать процесс до закрытия терминала. После закрытия терминала вы опять застрянете с процессом, который некуда выводить, если вы не перенаправили файл при запуске.

Чтобы обойти это, вы можете попытаться перенаправить вывод вашего процесса после того, как он уже запущен. Это выходит за рамки данного руководства, но вы можете взглянуть наthis post, чтобы понять, как это сделать.

Использование опции оболочки huponexit

В Bash также есть другой способ избежать проблемы SIGHUP для дочерних процессов. Параметр оболочкиhuponexit определяет, будет ли bash отправлять своим дочерним процессам сигнал SIGHUP при выходе.

Note

[.Примечание]##

Параметрhuponexit влияет на поведение SIGHUP только тогда, когда инициируется завершение сеанса оболочкиfrom within the shell itself. Некоторые примеры того, когда это применимо, - это когда в сеансе выполняется командаexit илиCTRL-D.

Когда сеанс оболочки завершается через саму программу терминала (путем закрытия окна и т. Д.), Командаhuponexit будет иметь эффектno. Вместо того, чтобыbash решал, следует ли отправлять сигнал SIGHUP, терминал сам отправит сигнал SIGHUP наbash, который затем (правильно) распространит сигнал на свои дочерние процессы.

Несмотря на приведенные выше предостережения, вариантhuponexit, пожалуй, один из самых простых. Вы можете увидеть, включена эта функция или нет, набрав:

shopt huponexit

Чтобы включить его, введите:

shopt -s huponexit

Теперь, если вы выйдете из сеанса, набравexit, все ваши процессы продолжат работу:

exit

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

Заключение

Обучение управлению заданиями и управлению приоритетными и фоновыми процессами даст вам большую гибкость при запуске программ из командной строки. Вместо того, чтобы открывать много окон терминала или сессий SSH, часто можно обойтись несколькими командами останова и фонового режима.

Related