Поиск по сайту:

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


Введение

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

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

Предпосылки

Чтобы следовать этому руководству, вам потребуется доступ к компьютеру с интерфейсом оболочки bash. bash — это оболочка по умолчанию во многих операционных системах на базе Linux, и она доступна во многих Unix-подобных операционных системах, включая macOS. Обратите внимание, что это руководство было проверено с использованием виртуального частного сервера Linux под управлением Ubuntu 20.04.

Если вы планируете использовать удаленный сервер, чтобы следовать этому руководству, мы рекомендуем вам сначала выполнить наше руководство по начальной настройке сервера. Это создаст для вас безопасную серверную среду, включая пользователя без полномочий root с привилегиями sudo и брандмауэр, настроенный с помощью UFW, которые вы сможете использовать для развития своих навыков работы с Linux.

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

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

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

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

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

  1. echo "Hello World"
Output
Hello World

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

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

  1. top

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

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

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

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

В отличие от top, такие циклы не имеют клавиши \выход. Вам придется остановить процесс, отправив ему сигнал. В Linux ядро может посылать сигналы запущенные процессы в качестве запроса на выход или изменение состояния. Терминалы Linux обычно настроены на отправку сигнала \SIGINT (сокращение от \прерывание сигнала) текущему процессу переднего плана, когда пользователь нажимает CTRL + C Комбинация клавиш Сигнал SIGINT сообщает программе, что пользователь запросил завершение с помощью клавиатуры.

Чтобы остановить начатый цикл, удерживайте клавишу CTRL и нажмите клавишу C:

CTRL + C

Цикл завершится, возвращая управление оболочке.

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

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

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

Еще один сигнал, который вы можете отправить, — это сигнал \SIGTSTP. SIGTSTP — это сокращение от \сигнал остановки терминала и обычно представляется как сигнал номер 20. Когда вы нажимаете CTRL + Z, ваш терминал регистрирует команду «приостановить», которая затем отправляет сигнал SIGTSTP процессу переднего плана. По сути, это приостановит выполнение команды и вернет управление терминалу.

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

  1. command ping -i 5 google.com

Вместо завершения команды с помощью CTRL + C нажмите вместо этого CTRL + Z. Это вернет вывод следующим образом:

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

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

  1. 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] сигналом управления заданием».

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

  1. fg

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

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

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

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

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

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

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

  1. command ping -i 5 google.com &

Система управления заданиями bash вернет следующий вывод:

Output
[1] 4287

После этого вы получите обычный вывод команды ping:

Output
PING 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:

  1. jobs

Если у вас по-прежнему работает предыдущая команда ping в фоновом режиме, вывод команды jobs будет примерно таким:

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

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

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

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

  1. kill %1

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

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

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

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

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

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

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

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

Первый шаг — снова остановить процесс с помощью CTRL + Z. Как только процесс будет остановлен, вы можете использовать команду bg, чтобы снова запустить его в фоновом режиме:

  1. bg

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

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

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

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

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

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

  1. fg

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

  1. fg %2

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

Работа с SIGHUP

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

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

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

Использование nohup

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

  1. nohup ping -i 5 google.com &

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

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

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

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

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

  1. pgrep -a ping
Output
7360 ping -i 5 google.com

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

  1. kill 7360

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

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

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

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

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

  1. disown %2

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

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

  1. disown -h %1

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

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

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

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

Примечание. Параметр huponexit влияет на поведение SIGHUP только тогда, когда завершение сеанса оболочки инициируется из самой оболочки. Некоторые примеры того, когда это применимо, — это когда в сеансе нажата команда exit или CTRL + D.

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

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

  1. shopt huponexit

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

  1. shopt -s huponexit

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

  1. exit

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

Заключение

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