Если остановитесь и немного задумаетесь, то станет довольно очевидно, что на вашем компьютере работает много программ. На самом деле в графическом режиме у вас может быть открыто несколько окон терминалов, браузер, игры, таблицы и другие приложения. В примерах мы вводили команды, ждали их выполнение и только потом могли продолжать работу. В разделе Использование командной строки мы столкнулись с командой ps, которая отображала статус процесса, и мы видели, что у процесса есть собственный номер Process ID (PID) и номер родительского процесса Parent Process id (PPID). В этом разделе, вы изучите, как выполнять больше задач в одном окне терминала.
Приоритетные и фоновые задачи
Когда вы выполняете команду в терминальном окне, как мы делали до этого, то вы запускали ее в приоритетном режиме. Наши команды работали довольно быстро, но предположим, что вы в графической среде и хотите запустить на рабочем столе цифровые часы. Не будем учитывать тот факт, что в большинстве сред они уже есть; мы просто рассматриваем как пример.
Если вы работаете в системе X Window, то возможно у вас есть такие утилиты как xclock или xeyes. Мы будем использовать xclock. В man-странице сказано, что вы можете запустить цифровые часы с помощью команды
xclock -d -update 1
Часть -update 1 является запросом на обновление часов раз в секунду, иначе стрелки часов обновлялись бы раз в минуту. Давайте запустим ее в терминальном окне. Мы увидим картину как на Рисунке Figure 2, а терминал будет выглядеть как в Листинге 82. Если у вас нет xclock или системы X Window, мы покажем, как создать в терминале простые часы, чтобы вы могли выполнить упражнения.
Листинг 82. Работающие часы xclock
[ian@echidna ian]$ xclock -d -update 1
К сожалению, терминальное окно больше не отображает приглашение, но нам надо как-то вернуться. К счастью, в Bash есть клавиша приостановки Ctrl-z. Нажав эту комбинацию, вы снова видите приглашение как показано в Листинге 83.
Листинг 83. Приостановление xclock с помощью Ctrl-z
[ian@echidna ian]$ xclock -d -update 1
[1]+ Stopped xclock -d -update 1
[ian@echidna ian]$
Часы все еще на рабочем столе, но они не работают. Произошло приостановление. На самом деле, если вы перетащите на него другое окно, но оно даже не перерисуется. Вы также видите, что на терминале отобразилось сообщение “[1]+ Stopped”. В сообщении 1 это номер задачи. Вы можете перезапустить часы, набрав fg %1. Вы также можете использовать имя команды или часть ее, набрав fg %xclock или fg %?clo. Наконец, вы можете просто использовать fg без параметров для перезапуска самой последней задачи, job 1 в нашем случае. Перезапуск с помощью fg также влечет возврат задачи в приоритетный режим, поэтому вы не видите приглашения. Что вам необходимо сделать, так это поместить задачу в фон; команда bg принимает те же параметры, что и команда fg и делает тоже самое. В Листинге 84 показано, как вернуть в приоритетный режим xclock и приостановить ее, используя две формы команды fg.. Вы можете снова ее приостановить и поместить в фон; часы будут работать, а вы сможете продолжать работу в терминале.
Листинг 84. Помещение xclock в фоновый режим работы
[ian@echidna ian]$ fg %1
xclock -d -update 1
[1]+ Stopped xclock -d -update 1
[ian@echidna ian]$ fg %?clo
xclock -d -update 1
[1]+ Stopped xclock -d -update 1
[ian@echidna ian]$ bg
[1]+ xclock -d -update 1 &
[ian@echidna ian]$
Использование “&”
Вы заметили, что, когда поместили xclock в фон, сообщение больше не гласило “Stopped” и что оно было завершено символом амперсанда (&). На самом деле, вам не надо приостанавливать процесс, чтобы помещать его в фон. Вы можете просто добавить в команду знак амперсанда, и shell интерпретатор запустит команду (или список команд) в фоном режиме. Давайте запустим аналоговые часы таким способом. Вы увидите часы как на Рисунке 3, а терминал будет выглядеть как в Листинге 85.
Листинг 85. Запуск xclock в фоне с помощью &
[ian@echidna ian]$ xclock -bg wheat -hd red -update 1&
[2] 5659
Заметим, что на этот раз сообщение немного отличается. Оно содержит номер задачи и идентификатор процесса (PID). Мы рассмотрим PID и его статус немного позже. Сейчас рассмотрим команду jobs для поиска запущенных задач. Добавим опцию -l, чтобы посмотреть PID процессов, и увидим, что задача 2 имеет PID 5659 как показано в Листинге 86. Заметим также, что у задачи 2 стоит знак плюс (+) перед номером, сигнализирующий, что это текущая задача. Эта задача также перейдет в приоритетный режим, если не будет задана никакая работа команде fg.
Листинг 86. Отображение работы и информации о процессе
[ian@echidna ian]$ jobs -l
[1]- 4234 Running xclock -d -update 1 &
[2]+ 5659 Running xclock -bg wheat -hd red -update 1 &
Прежде, чем будем рассматривать другие вопросы, связанные с задачами, реализуем сами цифровые часы. Мы будем использовать команду sleep для создания задержки на две секунды, а затем используем команду date для выдачи текущей даты и времени. Мы вставим эти команды в цикл while, используя блок do/done для создания бесконечного цикла. Наконец, мы используем круглые скобки для создания списка команд и переведем весь список в фоновой режим с помощью амперсанда.
Листинг 87. Цифровые часы
[ian@echidna ian]$ (while sleep 2; do date;done) &
[1] 16291
[ian@echidna ian]$ Thu Nov 10 22:58:02 EST 2005
Thu Nov 10 22:58:04 EST 2005
Thu Nov 10 22:58:06 EST 2005
Thu Nov 10 22:58:08 EST 2005
fThu Nov 10 22:58:10 EST 2005
Thu Nov 10 22:58:12 EST 2005
gThu Nov 10 22:58:14 EST 2005
( while sleep 2; do
date;
done )
Thu Nov 10 22:58:16 EST 2005
Thu Nov 10 22:58:18 EST 2005
Как и ожидали, наш список выполняется как задача 1 с PID 16291. Каждые две секунды команда date выдает на терминал время и текущую дату. Ваш ввод выделен шрифтом. При медленном наборе символы будут рассеяны по экрану, прежде чем будет набрана вся команда. На самом деле заметим, что ‘f’ ‘g’, которые мы напечатали для выдачи списка в приоритетный режим, находятся на двух строках. После того, как мы ввели команду fg, bash отобразит команду, которая сейчас работает в интерпретаторе, а именно, список команд, который продолжает работать каждые две секунды.
Как только мы перевели задачу в приоритетный режим, то можем как завершить задачу (или убить), так и предпринять какое-либо другое действие. В этом случае мы используем Ctrl-c для завершения работы наших часов.
Стандартный ввод/вывод и фоновые процессы
Вывод команды date в предыдущем примере рассеян вместе с символами команды fg, которую мы пытались набрать. Встает интересный вопрос. Что случится с процессом, если ему требуется ввод из stdin?
Терминальный процесс, в котором мы запустили фоновое приложение, называется контролирующим терминалом. В случае не использования перенаправления, потоки stdout и stderr фонового процесса направляются на контролирующий терминал. Также фоновая задача ожидает ввод от контролирующего терминала, но у контролирующего терминала нет способа передать ваши символы в stdin фонового процесса. В таком случае Bash приостанавливает процесс, так что он больше не исполняется. Вы можете вывести его в приоритетный режим и предоставить необходимый ввод. Листинг 88 иллюстрирует простые примеры, в которых вы переключаете список команд в фоновый режим. Через некоторое время нажимаете Enter и процесс останавливается. Переводите задачу в приоритетный режим, предоставляете строку ввода, за которой следует сигнал окончания ввода Ctrl-d файла. Список команд завершается, и мы отображаем созданный файл.
Листинг 88. Ожидание stdin
[ian@echidna ian]$ (date; cat - >bginput.txt; date)&
[1] 18648
[ian@echidna ian]$ Fri Nov 11 00:03:28 EST 2005
[1]+ Stopped ( date; cat - >bginput.txt; date )
[ian@echidna ian]$ fg
( date; cat - >ginput.txt; date )
input data
Fri Nov 11 00:03:53 EST 2005
[ian@echidna ian]$ cat bginput.txt
input data
Задачи без терминалов
На практике вы возможно захотите осуществлять ввод\вывод для фоновых процессов из или в файлы Встает другой вопрос; что случится с процессом, если контролирующий терминал закроется или пользователь выйдет из системы? Ответ зависит от используемого интерпретатора. Если он посылает сигнал SIGHUP (или зависание), то приложение закроется. Мы коротко рассмотрим сигналы, а сейчас рассмотрим другой способ решения этой проблемы.
nohup
Команда nohup используется для запуска команды, которая будет игнорировать сигналы зависания и добавлять stdout и stderr в файл. По умолчанию это файл nohup.out или $HOME/nohup.out. Если писать в файл нельзя, то команда не запустится. Если вы хотите, то можете перенаправить куда угодно stdout или stderr как мы уже узнали из предыдущего раздела этого руководства.
Еще одной особенностью nohup является то, что она не будет выполнять конвейер или список команд. В теме Перенаправление стандартного ввода\вывода Мы рассмотрели, как использовать сценарии. Вы можете сохранить конвейер или список команд в файл и запустить его с помощью sh (интерпретатором по умолчанию) или командой bash, хотя вы не можете использовать команду . или source как мы делали в примере ранее. В следующем руководстве этой серии (по теме 104, рассказывающем об Устройствах, файловых системах Linux, структуре файловой системы) мы покажем, как сделать сценарий исполняемым, но сейчас мы будем использовать команду sh или bash. Листинг 89 показывает, как это можно сделать с нашими написанными часами. Не стоит и говорить, что запись времени в файл не особенно полезна, кроме того, файл будет расти в размере, поэтому мы установим интервал обновления каждые 30 секунд.
Листинг 89. Использование nohup и сценария
[ian@echidna ian]$ echo "while sleep 30; do date;done">pmc.sh
[ian@echidna ian]$ nohup . pmc.sh&
[1] 21700
[ian@echidna ian]$ nohup: appending output to `nohup.out'
[1]+ Exit 126 nohup . pmc.sh
[ian@echidna ian]$ nohup sh pmc.sh&
[1] 21709
[ian@echidna ian]$ nohup: appending output to `nohup.out'
[ian@echidna ian]$ nohup bash pmc.sh&
[2] 21719
[ian@echidna ian]$ nohup: appending output to `nohup.out'
Если отобразим содержимое nohup.out, то увидим, что первая строка отображает причину получения кода выхода 126 в нашей первой попытке выше. Последующие строки являются выводом двух версий pmc.sh, которые сейчас работают в фоне. Это проиллюстрировано в Листинге 90.
Листинг 90. Вывод не прерванных процессов
[ian@echidna ian]$ cat nohup.out
/bin/nice: .: Permission denied
Fri Nov 11 15:30:03 EST 2005
Fri Nov 11 15:30:15 EST 2005
Fri Nov 11 15:30:33 EST 2005
Fri Nov 11 15:30:45 EST 2005
Fri Nov 11 15:31:03 EST 2005
Сейчас обратим внимание на статус процесса. Если вы планируете передохнуть, то не спешите, так как вам предстоит создать еще две задачи, которые создадут еще большие файлы в вашей системе. Вы можете использовать команду fg, чтобы перевести каждый процесс в приоритетный режим, а затем использовать Ctrl-c для его завершения, и если вы позволите им поработать чуть подольше, то увидим другие способы мониторинга и взаимодействия с ними.
Статус процесса
В предыдущих частях этого раздела мы познакомились с командой jobs и увидели, как использовать ее для просмотра Process ID (или PID) наших задач.
ps
Есть другая команда, команда ps, которая отображает различную информацию о статусе процесса. Помните, что “ps” это акроним от “process status”. Команда ps принимает ноль или более номеров PID в качестве аргументов и отображает статус соответствующих процессов. Если использовать команду jobs с опцией -p, то вывод будет представлять собой PID лидера группы процессов каждой задачи. Мы будем использовать вывод этой команды как аргументы команды ps, что и показано в Листинге 91.
Листинг 91. Статус фоновых процессов
[ian@echidna ian]$ jobs
[1]- Running nohup sh pmc.sh &
[2]+ Running nohup bash pmc.sh &
[ian@echidna ian]$ jobs -p
21709
21719
[ian@echidna ian]$ ps `jobs -p`
PID TTY STAT TIME COMMAND
21709 pts/3 SN 0:00 sh pmc.sh
21719 pts/3 SN 0:00 bash pmc.sh
Если используем команду ps без всяких опций, то увидим список процессов, которые контролируются текущим терминалом как показано в Листинге 92.
Листинг 92. Отображение статуса с помощью ps
[ian@echidna ian]$ ps
PID TTY TIME CMD
20475 pts/3 00:00:00 bash
21709 pts/3 00:00:00 sh
21719 pts/3 00:00:00 bash
21922 pts/3 00:00:00 sleep
21930 pts/3 00:00:00 sleep
21937 pts/3 00:00:00 ps
Некоторые опции как -f (full), -j (jobs), и -l (long) позволяет отобразить информацию с нужной точностью. Если мы не определим никаких номеров PID, то существует другая полезная опция –forest, которая отображает команды в виде дерева, показывая порождение процессов. В частности, мы видим, что команды sleep предыдущего листинга являются детьми сценариев, которые мы запустили в фоновом режиме. Если мы запустим эту команду в другой момент времени, то можем увидеть команду date в списке процессов, однако на этом примере трудно увидеть другие расхождения. Проиллюстрируем на примере Листинга 93.
Листинг 93. Расширенная информация о статусе процессов
[ian@echidna ian]$ ps -f
UID PID PPID C STIME TTY TIME CMD
ian 20475 20474 0 15:02 pts/3 00:00:00 -bash
ian 21709 20475 0 15:29 pts/3 00:00:00 sh pmc.sh
ian 21719 20475 0 15:29 pts/3 00:00:00 bash pmc.sh
ian 21945 21709 0 15:34 pts/3 00:00:00 sleep 30
ian 21953 21719 0 15:34 pts/3 00:00:00 sleep 30
ian 21954 20475 0 15:34 pts/3 00:00:00 ps -f
[ian@echidna ian]$ ps -j --forest
PID PGID SID TTY TIME CMD
20475 20475 20475 pts/3 00:00:00 bash
21709 21709 20475 pts/3 00:00:00 sh
21945 21709 20475 pts/3 00:00:00 \_ sleep
21719 21719 20475 pts/3 00:00:00 bash
21953 21719 20475 pts/3 00:00:00 \_ sleep
21961 21961 20475 pts/3 00:00:00 ps
Список других процессов
Команды ps, которые мы использовали в примерах, выдавали список только тех процессов, которые запущены через терминал (обратим внимание на столбец SID во втором примере Листинга 93). Чтобы увидеть все процессы, контролируемые терминалами, используйте опцию -a. Опция -x отобразит процессы без контролирующего терминала, а опция -e отобразит информацию для каждого процесса. В Листинге 94 приведен полный формат всех процессов, контролируемых терминалом.
Листинг 94. Отображение остальных процессов
[ian@echidna ian]$ ps -af
UID PID PPID C STIME TTY TIME CMD
ian 4234 32537 0 Nov10 pts/0 00:00:00 xclock -d -update 1
ian 5659 32537 0 Nov10 pts/0 00:00:00 xclock -bg wheat -hd red -update
ian 21709 20475 0 15:29 pts/3 00:00:00 sh pmc.sh
ian 21719 20475 0 15:29 pts/3 00:00:00 bash pmc.sh
ian 21969 21709 0 15:35 pts/3 00:00:00 sleep 30
ian 21977 21719 0 15:35 pts/3 00:00:00 sleep 30
ian 21978 20475 0 15:35 pts/3 00:00:00 ps -af
Заметим, что этот список включает два процесса xclock, которые мы запустили ранее в графическом режиме этой системы (о чем свидетельствует pts/0), в то время как оставшиеся процессы ассоциированы с ssh (Secure Shell) соединением (pts/3 в этом случае).
Существует множество опций у команды ps, которые позволяют отобразить нужную информацию. Например, опции, позволяющие отобразить процессы конкретного пользователя. За подробностями обращайтесь к man-страницам команды ps или же можете получить краткое описание, используя команду ps –help.
top
Если вы используете команду ps несколько раз к ряду, чтобы увидеть различные изменения, то возможно вам стоит вместо нее использовать команду top. Она выводит постоянно обновляющийся список процессов и некоторую полезную информацию. Смотри man-страницы top, чтобы узнать о списке опций, а также о том, как сортировать процессы по объему используемой памяти или другим критериям. В Листинге 95 показано несколько первых строк вывода команды top.
Листинг 95. Вывод других процессов
3:37pm up 46 days, 5:11, 2 users, load average: 0.01, 0.17, 0.19
96 processes: 94 sleeping, 1 running, 0 zombie, 1 stopped
CPU states: 0.1% user, 1.0% system, 0.0% nice, 0.9% idle
Mem: 1030268K av, 933956K used, 96312K free, 0K shrd, 119428K buff
Swap: 1052216K av, 1176K used, 1051040K free 355156K cached
PID USER PRI NI SIZE RSS SHARE STAT %CPU %MEM TIME COMMAND
22069 ian 17 0 1104 1104 848 R 0.9 0.1 0:00 top
1 root 8 0 500 480 444 S 0.0 0.0 0:04 init
2 root 9 0 0 0 0 SW 0.0 0.0 0:00 keventd
3 root 9 0 0 0 0 SW 0.0 0.0 0:00 kapmd
4 root 19 19 0 0 0 SWN 0.0 0.0 0:00 ksoftirqd_CPU0
5 root 9 0 0 0 0 SW 0.0 0.0 0:00 kswapd
Сигналы
Рассмотрим теперь сигналы в Linux. Они являются асинхронным средством взаимодействия с процессами. Мы уже упомянули сигнал SIGHUP, а также использовали комбинации Ctrl-c и Ctrl-z для посылки сигнала процессам. Главный способ посылки сигнала состоит в использовании команды kill.
Посылка сигналов с помощью kill
Команда kill посылает сигнал определенной задаче или процессу. Листинг 96 содержит пример использования сигналов SIGTSTP и SIGCONT для остановки и возобновления фоновой задачи. Использование сигнала SIGTSTP эквивалентно использованию команды fg для перевода задачи в приоритетный режим, а затем Ctrl-z для ее приостановки. Действие сигнала SIGCONT похоже на работу команды bg.
Листинг 96. Остановка и запуск фоновых задач
[ian@echidna ian]$ kill -s SIGTSTP %1
[ian@echidna ian]$ jobs -l
[1]+ 21709 Stopped nohup sh pmc.sh
[2]- 21719 Running nohup bash pmc.sh &
[ian@echidna ian]$ kill -s SIGCONT %1
[ian@echidna ian]$ jobs -l
[1]+ 21709 Running nohup sh pmc.sh &
[2]- 21719 Running nohup bash pmc.sh &
В этом примере мы использовали номер задачи (%1), но вы также можете посылать сигналы по идентификатору процесса (то есть 21709 является PID задачи %1). Если вы используете команду tail в то время как задача %1 остановлена, то только один процесс изменит файл nohup.out.
Существует всевозможное множество сигналов в вашей системе, которые вы можете отобразить с помощью команды kill -l. Некоторые используются для сообщения об ошибках, например для сообщения о неверных кодах операции, исключения при работе с плавающей точкой или попытке обратится к памяти другого процесса. Заметим, что у сигналов есть как номер, например, 20, так и имя, например, SIGTSTP. Вы можете использовать как номер, так и имя с помощью опции -s. Следует всегда проверять номера сигналов на системе, прежде чем делать какие-либо предположения о сигналах.
Обработчики сигналов и завершение процесса
Мы уже видели, что Ctrl-c завершает процесс. На самом деле она посылает сигнал SIGINT (или прерывание) процессу. Если вы используете kill без указания сигнала, то система пошлет сигнал SIGTERM. Для большинства применений эти два сигнала эквивалентны.
Мы сказали, что команда nohup иммунизирует процесс от восприятия сигнала SIGHUP. В общем случае процесс может реализовать обработчик сигнала для перехвата сигналов. Поэтому процесс может реализовать обработчик сигнала для перехвата как SIGINT так и SIGTERM. Так как обработчик сигнала знает, какой сигнал был послан, он может, например, проигнорировать сигнал SIGINT и завершить работу только при получении сигнала SIGTERM. В Листинге 97 показано, как послать сигнал SIGTERM задаче %1. Заметим, что статус процесса изменился на “Завершен” сразу после того, как мы послали сигнал. Статус изменится на “Прерван”, если мы пошлем сигнал SIGINT. Через несколько мгновений произойдет очистка процессов, и теперь задача больше на находится в списке задач.
Листинг 97. Завершение процесса с помощью SIGTERM
[ian@echidna ian]$ kill -s SIGTERM %1
[ian@echidna ian]$ jobs -l
[1] 21709 Terminated nohup sh pmc.sh
[2]- 21719 Running nohup bash pmc.sh &
[ian@echidna ian]$ jobs -l
[2]+ 21719 Running nohup bash pmc.sh &
Обработчики сигналов предоставляют процессу гибкость в том, что он может выполнять свою обычную работу и прерываться по сигналу только для особых целей. Кроме того, что процесс может перехватить запросы на окончание работы и возможно предпринять определенные действия, как например закрытие файлов или проверить работу текущей транзакции, сигналы часто используются, чтобы сообщить демону о его перезапуске и повторном прочтении файла конфигурации. Вы можете сделать это с процессом inetd, чтобы ваши изменения параметров сети вступили в силу или послать сигнал демону печати (lpd), когда добавляете новый принтер.
Безаппеляционное завершение процессов
Некоторые сигналы не могут быть перехвачены, как например некоторые аппаратные исключения. SIGKILL, который скорее всего вы будете использовать, нельзя отловить обработчиком сигналов, и он используется для завершения процесса. В общем случае его следует использовать только, когда другие средства завершения работы процесса не помогают.
Logout и nohup
Помните, мы говорили, что команда nohup позволит всем нашим процессам продолжать работу после нашего выхода из системы. Давайте сделаем это, а затем снова войдем в систему. После нашего возвращения проверим статус процесса, исполняющего наши написанные часы с помощью jobs и ps как мы уже делали до этого. Вывод представлен в Листинге 98.
Листинг 98. Повторный заход в систему
[ian@echidna ian]$ jobs
[ian@echidna ian]$ ps -a
PID TTY TIME CMD
4234 pts/0 00:00:00 xclock
5659 pts/0 00:00:00 xclock
27217 pts/4 00:00:00 ps
Мы видим, что работаем в этот раз на pts/4, но наших задач нет и следа, как будто мы только запустили команду ps и два процесса xclock в графическом режиме с терминала (pts/0). Не совсем то, что мы ожидали увидеть. Однако не все потеряно. В Листинге 99 мы покажем один способ как найти потерянные задачи с помощью опции -s означающей идентификатор сессии, а также идентификатор сессии 20475, который мы видели в Листинге 93. Подумайте о других способах обнаружения задач для случая, если вы не знаете идентификатора сессии.
Листинг 99. Повторный заход в систему
[ian@echidna ian]$ ps -js 20475
PID PGID SID TTY TIME CMD
21719 21719 20475 ? 00:00:00 bash
27335 21719 20475 ? 00:00:00 sleep
Зная о том, как убивать процессы, вы можете убить их, используя PID и команду kill.
Взято с ibm developerworks