четверг, 27 мая 2010 г.

Управление выполняющимися процессами в шелле

Уверен, многие новички, пытаясь пользоваться шеллом, наивно полагают, что в одном терминале может выполняться только одно приложение. Чуть более продвинутые слышали о (якобы монструозном) screen'е, позволяющим делать разные страшные штуки, в том числе запускать в одной консоли много приложений сразу. При этом очень полезные built-in команды часто остаются незамеченными. О них и пойдёт речь.

Сразу замечу, что в посте будут описаны bash и zsh. Другие шеллы могут не поддерживать указанных команд.

Итак, представим себе ситуацию: вы запустили какую-то долго выполняющуюся команду, скажем, find, и ждёте её вывода. Тут у вас появилась какая-то идейка, и вы уже тянетесь к клавиатуре, но шелл ведь занят, верно? Не беда — жмите ctrl+z и воплощайте идею в жизнь. Когда закончите, наберите fg %1 — и прерванная команда продолжит выполняться.

Давайте теперь разберём, как же это работает. Когда вы нажимаете ctrl+z, текущий процесс приостанавливается («suspend» — «приостанавливать»). Следует понимать, что пока процесс приостановлен, он никак не реагирует на внешние раздражители — например, если вы приостановили какое-то графическое приложение, его окно не будет перерисовываться, а если это был wget — он не будет ничего качать.

Команда fg (название которой, как вы догадались, происходит от «foreground» — «передний план») выполняет абсолютно противоположную задачу — она запускает (можно сказать, снимает с паузы) приостановленное приложение. Аргумент указывает на то, какую именно задачу следует запустить.

Из предыдущего абзаца можно сделать два полезных вывода:
  1. вы можете приостанавливать более чем одну задачу одновременно;
  2. каждая приостановленная задача имеет свой собственный номер, так что ими легко оперировать.
Таким образом мы приходим к третьей команде — jobs. Несложно догадаться, что она выводит список всех задач вместе с их номерами.

Менее очевидной, но всё же верной догадкой является то, что помимо fg должна существовать и парная ей команда bgbackground» — «фон»). Её задача — продолжить выполнение приостановленного процесса в фоне. Очень удобно с командами, вывод которых перенаправлен в файл: они ведь ничего не выводят на экран, так что нам нечего пялиться на занятый шелл — поместили её в фон и работаем дальше. Синтаксис bg ничем не отличается от оного у fg — команда принимает на вход номер задачи, выполнение которой следует продолжить в фоне. Кстати, отправить задачу в фон можно сразу же — достаточно просто дописать в конце команды амперсанд, например, вот так:
updatedb &


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

К счастью, даже для такой задачи у шелла есть решение, а имя ему — disown. Эта команда делает именно то, что нам нужно — она открепляет определённую задачу от шелла. Синтаксис ничем не отличается от fg и bg — команда принимает номер задачи. Команду также можно использовать вот в таком виде:
command & disown
(обратите внимание, что амперсанд всего один!) При этом процесс, созданный командой command, сразу же открепляется от шелла, так что вам не надо ничего больше вводить. Счастливые пользователи ZSH могут использовать сокращённую запись:
command &!

Правда, disown имеет некую специфику — если выполнить её для приостановленной задачи, задача так и останется приостановленной. Выход — сигнал CONT. После того, как сделали disown приостановленной задачи, наберите:
kill -CONT PID
где PID — это номер процесса, который мы только что открепили от консоли. Не пугайтесь команды kill — она вовсе не обязательно убивает процесс: как видите, с её помощью можно мирно передавать процессам какие-то команды (ещё один пример такого поведения — conky: если выполнить kill -USR1 PID, коньки перечитают свой конфиг). Отдельное слово также надо сказать про PID — BASH говорит его сам:
bash: warning: deleting stopped job 1 with process group 23710
(последнее число и есть искомый IDшник), а ZSH и вовсе выдаёт готовую команду:
disown: warning: job is suspended, use `kill -CONT -24309' to resume

Собственно, на этом разговор об управлении процессами в шелле можно считать законченным. В качестве дополнительной литературы могу посоветовать вывод help fg, help bg, help jobs и help disown. До встречи!

Копируете статью — поставьте ссылку!

11 комментариев:

bosha комментирует...

Вместо disown можно ещё использовать nohup: nohup command. Если шелл закрыть, процесс останется.

Minoru комментирует...

Так и знал, что кто-то таки спалит :) Короче, про screen, nohup и dtach — тссс! Про них я ещё напишу.

Анонимный комментирует...

можно включить новый tab и ничего не нужно прерывать

Minoru комментирует...

> можно включить новый tab и ничего не нужно прерывать
Можно. Но в tty, например, вы не найдёте табов, как, впрочем, и в легковесных исковых терминалах (xterm, емнип, не умеет). Да и в любом случае — неужели Вы, уважаемый анонимус, против получения новых знаний?

Pavel Vyazovoi комментирует...

>> Короче, про screen, nohup и dtach — тссс!

tmux не забудь

Minoru комментирует...

> tmux не забудь
М! Слышал о нём, но не знал, что он из этой оперы. Постараюсь разобраться и написать, спасибо за подсказку!

bosha комментирует...

>tmux не забудь

Ей! Не пали. У меня статья завтра про него опубликуется ;)

Анонимный комментирует...

Здорово, наконец-то узнал как продолжить команду в фоне (bg). Да и здесь Вы описались: "Синтаксис bg ничем не отличается от оного у fg — команда принимает на вход номер задачи, которую следует отправить в фон." Должно быть типа "..активировать фоновую задачу"

Minoru комментирует...

> Да и здесь Вы описались: "Синтаксис bg ничем не отличается от оного у fg — команда принимает на вход номер задачи, которую следует отправить в фон." Должно быть типа "..активировать фоновую задачу"
Да, формулировку следовало бы поправить. Сейчас займусь. Спасибо за комментарий!

Beggy комментирует...

Век живи, век учись :)) Запись %1 меня поначалу смутила, но теперь после прочтения соответствующей секции man bash понимаю, что это как раз правильный способ.
Если позволите, я бы все-таки где нибудь вставил мысль, что все это внутренние команды конкретного shell (например bash) и они могут не поддерживаться или поддерживаться иначе в других. И пару слов о главном герое "&" - именно с него у новичков обычно начинается знакомство с "фоновыми" задачами.
А так - спасибо. Хорошая статья - буду рекомендовать :)

Minoru комментирует...

Спасибо, Beggy! С амперсандом я и правда дал маху :)

Добавил пару предложений в абзац о fg, а в начале поста дописал абзацик о том, что речь идёт о bash/zsh.

Отправить комментарий

Примечание. Отправлять комментарии могут только участники этого блога.

 
Blogger logo Debian logo Creative Commons License FeedBurner Subscribers Counter