Содержание


Планирование и автоматизация выполнения заданий средствами командной оболочки shell

Часть 1. Простейшие средства

Comments

Серия контента:

Этот контент является частью # из серии # статей: Планирование и автоматизация выполнения заданий средствами командной оболочки shell

Следите за выходом новых статей этой серии.

Этот контент является частью серии:Планирование и автоматизация выполнения заданий средствами командной оболочки shell

Следите за выходом новых статей этой серии.

1. Введение. Автоматизация повышает эффективность

Пользователи Unix-подобных систем достаточно часто оказываются в ситуации, когда какая-либо программа или операция должна быть выполнена "минут через 15", "сегодня вечером", "завтра в 12:00", "каждую пятницу в 23 часа" и т.п. Даже обладая феноменальной памятью и пытаясь в нужное время вручную запускать все необходимые программы, вы рискуете забыть что-то важное. Впрочем, большинству пользователей описанная проблема покажется надуманной, ведь в каждом современном дистрибутиве предлагается на выбор около десятка приложений, позволяющих её решить (планировщики, таймеры, "будильники" и прочее). Но в данной статье речь пойдёт не о них.

Мы будем рассматривать средства автоматизации и планирования, предлагаемые командной оболочкой shell. У тех, кто привык к графическому интерфейсу и с трудом представляет себе, как можно без него обходиться, наверняка возникнет вопрос: "Почему именно средства командной оболочки? Ведь есть же более удобные GUI-программы". Во-первых, изучая и используя функциональные возможности командной оболочки и её утилит, вы повышаете свою квалификацию и получаете в своё распоряжение эффективные инструменты. Во-вторых, эти "удобные GUI-приложения" зачастую представляют собой не что иное, как графическую оболочку, в которую "обёрнуты" либо те же самые утилиты, либо скрипты командной оболочки shell, поэтому, поняв, как работает "внутренний механизм", вы сможете извлечь больше пользы. Кроме всего прочего, применение средств командной оболочки позволяет более рационально эксплуатировать аппаратные ресурсы (в первую очередь – оперативную память).

2. Автоматизация с помощью простых средств (sleep, &, nohup)

2.1. Сделаем паузу...

Несложное планирование времени выполнения разнообразных операций можно осуществлять с помощью штатной утилиты sleep ("штатной" – потому, что она входит в пакет coreutils, устанавливаемый в составе любого дистрибутива). Стандартная версия этой команды предельно проста – она позволяет обеспечить паузу длиной в количество секунд, задаваемое целым числом. В сочетании с функцией перевода команды, последовательности команд или скрипта в фоновый режим, которая активизируется, если в конце командной строки задан символ "амперсэнд" (&), можно быстро создать простейшее напоминание, например, о том, что через десять минут необходимо позвонить:

(sleep 600; echo "Позвонить руководителю проекта.") &

О переводе в фоновый режим с помощью завершающего строку символа '&' более подробный разговор у нас ещё впереди. Сейчас достаточно знать о том, что команды, запускаемые в этом режиме, "исчезают" из поля нашего зрения и позволяют продолжить работу в командной оболочке. Через заданное время они напоминают о себе, т.е. в данном примере через десять минут на консоль будет выведено указанное сообщение.

В GNU-версию sleep добавлены небольшие усовершенствования. Во-первых, числовое значение может сопровождаться буквенными суффиксами, обозначающими единицы измерения времени: s – секунды (можно не указывать, так как измерение в секундах принято по умолчанию), m – минуты, h – часы, d – дни. Кроме того, числовое значение может быть не только целым, но и числом с плавающей точкой. Если в командной строке указано несколько числовых значений, то длина паузы будет вычислена как сумма этих значений (это удобно при использовании в скриптах, когда длина паузы вычисляется по значениям нескольких переменных).

Поэтому приведённую выше команду при использовании GNU-версии sleep можно записать так:

(sleep 10m; echo "Позвонить руководителю проекта.") &

Если у вас имеется некий скрипт, обрабатывающий большие дисковые файлы с созданием резервных копий, и вы хотите контролировать объём остающегося свободным дискового пространства, то можно записать такую команду:

(my_script.sh; sleep 30m; df -h; sleep 30m; df -h; sleep 30m; df -h) &

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

2.2. Из интерактивного в фоновый и обратно

При работе в командной оболочке shell различают два режима выполнения команд: интерактивный (foreground) и фоновый (background). В интерактивном режиме в любой момент времени выполняется только одна команда, с которой взаимодействует пользователь (через устройство стандартного ввода – обычно это клавиатура, и устройство стандартного вывода – консоль или окно эмулятора терминала). В фоновом режиме поддерживается одновременное выполнение нескольких программ без возможности непосредственного взаимодействия пользователя с ними. Количество программ, работающих в фоновом режиме, ограничено только доступными системными ресурсами.

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

$ make all &
[1] 30971
$

Реакцией командной оболочки на инициализацию фонового режима является вывод номера задания в квадратных скобках и соответствующего идентификатора процесса (PID). После этого выводится промпт командной оболочки ($), сообщающий о том, что shell готов принять от вас новую команду, т.е. продолжить работу в интерактивном режиме.

Допустим, что у нас есть скрипт, генерирующий отчёт на основе данных, собираемых из системных журналов (logs). Очевидно, что выполнение этого скрипта занимает много времени, поэтому имеет смысл также запустить его в фоновом режиме:

$ logs_report.sh &
[2] 30977
$

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

Список всех программ, выполняющихся в фоновом режиме, выводится с помощью встроенной команды jobs:

$ jobs
[1]-  Running     make all &
[2]+  Running     logs_report.sh &
$

Перевод выполняемого задания из фонового режима в интерактивный осуществляется командой fg. Если в списке несколько фоновых заданий, то в качестве аргумента этой команде передаётся порядковый номер задания с обязательным префиксом – символом процента (%). Например, для перевода процесса сборки программного проекта в интерактивный режим команда будет выглядеть так:

fg %1

Если выполнить команду fg без аргументов, то в интерактивный режим будет переведено задание, помеченное знаком плюс (+) в списке заданий.

Программу, выполняющуюся в интерактивном режиме, можно временно приостановить (не завершая полностью её выполнение) с помощью комбинации клавиш Ctrl+Z. (Вообще говоря, это сочетание клавиш помогает и в тех случаях, когда невозможно определить текущее состояние программы – "то ли зависла, то ли слишком долго работает", или когда программа не реагирует на прочие нажатия клавиш, в том числе и на Ctrl+C.)

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

$ make all
^Z
[1]+  Stopped     make all
$ bg
[1]+  make all &
$

Непосредственно после ввода make all промпт не появляется, так как начинается сборка проекта в интерактивном режиме. После того как нажаты клавиши Ctrl+Z, текущий интерактивный процесс приостанавливается, и выводится строка его нового состояния (Stopped – приостановлен). Здесь уже появляется промпт командной оболочки, и вы можете ввести любую команду. В данном случае выполняется команда bg, переводящая приостановленный процесс в фоновый режим.

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

Для того чтобы прекратить выполнение задания в фоновом режиме, можно вместо идентификатора процесса (PID) воспользоваться номером задания, например:

kill %1

При выполнении команды kill будьте внимательны: если вы пропустите символ '%', то числовое значение будет интерпретировано как идентификатор процесса. Другими словами, если вы обладаете правами суперпользователя (root) в момент выполнения этой команды, то рискуете "уничтожить" процесс init с идентификатором 1, являющийся прародителем всех прочих процессов в системе.

Будем считать, что вы работаете как обычный пользователь, и при вводе команды не совершили никаких ошибок и опечаток. После ввода команды kill %1 вначале кажется, что ничего не изменилось: выводится очередной промпт и... всё. Но если нажать клавишу Enter ещё раз, то появится следующее сообщение:

[1]+  Завершено(Terminated)      make all

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

При наличии нескольких заданий, выполняющихся в фоновом режиме, к ним можно обращаться не только по номерам (как это было показано ранее), но и по именам. Предположим, что имеются два фоновых задания:

$ jobs
[1]-  Running    make all &
[2]+  Running    logs_report.sh &
$ kill %logs_report.sh
$ fg %make

Выполнение задания по формированию отчётов завершается, а процесс сборки проекта переводится в интерактивный режим. Единственный недостаток этого способа (с точки зрения многих пользователей) – слишком много символов приходится вводить с клавиатуры. Конечно, полностью избавиться от ввода с клавиатуры не удастся, но и эту работу можно облегчить, если непосредственно после символа % ввести знак вопроса, после которого вводится лишь часть командной строки задания. Главное условие – эта часть должна однозначно определять имя задания. Например:

kill %?log

или

kill %?rep

Ещё один "подарок" для тех, кто не любит вводить длинные командные строки. Для перевода любого фонового задания в интерактивный режим вместо команды

fg %2

можно ввести просто

%2

2.3. Команда nohup

Все выполняющиеся в фоновом режиме задания, безусловно, завершаются (фактически уничтожаются), когда запустивший их пользователь выходит из сеанса командной оболочки (logout в текстовой консоли; закрытие окна эмулятора терминала в X Window и т.д.). Но вы можете сделать так, чтобы даже после завершения сеанса работы в системе продолжалось независимое выполнение вашего задания. Для этого запустите его с помощью команды nohup. Общий формат этой команды выглядит следующим образом:

nohup <команда> &

Идея заключается в том, чтобы игнорировать сигнал HUP (Hang UP – разрыв связи с терминалом), который посылается всем процессам пользователя при выходе из сеанса его работы. При получении этого сигнала обычные процессы завершаются в обязательном порядке. Процесс, запускаемый с помощью nohup, продолжает своё выполнение.

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

nohup команда > файл_вывода 2>&1 &

В данном случае к потоку вывода присоединяется ещё и поток сообщений об ошибках.

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

$ nohup ./script.sh &
nohup: ввод игнорируется, вывод добавляется в 'nohup.out'
[2] 5111
$

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

$ ps x | grep script
 5111 pts/0   RN   0:07 /bin/sh ./script.sh
 5178 pts/0   S+   0:00 grep script

В третьем столбце указан статус процесса: R – процесс выполняется, N – признак понижения приоритета, что характерно для большинства nohup-заданий. В четвёртом столбце – суммарное время использования процессора.

Теперь выйдем из командной оболочки, выполнив команду logout (exit) или просто закрыв окно терминала, затем снова запустим сеанс shell и введём ещё раз команду просмотра процессов:

$ ps x | grep script
 5111 ?       RN   2:18 /bin/sh ./script.sh
 5283 pts/1   S+   0:00 grep script

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

3. Чем может помочь команда screen

Ещё одним средством распараллеливания выполнения заданий является утилита screen, которая позволяет запускать на одном терминале несколько экземпляров командной оболочки shell с возможностью произвольного перехода между ними.

Например, вы работаете с файлом в редакторе vim, и возникает необходимость просмотра справочного руководства man. Разумеется, можно выйти из vim или воспользоваться встроенной функцией временного выхода в shell. Но если использовать программу screen, то вы сможете просто переходить из одного экземпляра командной оболочки в другой, не выходя из открытых программ. В одном экземпляре открыт vim и редактируется файл, в другом – открыта нужная страница man, в третьем – выполняется поиск требуемого файла и т.д. Всего можно создать до десяти экземпляров командных оболочек в screen. Да, я знаю про текстовые виртуальные консоли и про то, что в эмуляторах терминалов можно создавать экземпляры командных оболочек в отдельных вкладках, да и вообще открыть сколько угодно окон терминалов, но screen обладает некоторыми весьма интересными возможностями.

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

При необходимости обратиться к справочной системе man, вовсе не нужно выходить из редактора, а просто нажать клавиши Ctrl+A Ctrl+C, чтобы активизировать второй экземпляр командной оболочки в новом экране с номером 1. Снова появляется стандартный промпт, и можно открыть нужную страницу руководства. Получив требуемую информацию, вы нажимаете клавиши Ctrl+A Ctrl+A и возвращаетесь в экран 0, где продолжаете работу в редакторе vim. Комбинации клавиш Ctrl+A Ctrl+A работают как переключатели между экранами. Нужно найти какой-либо файл с помощью команды find? Откройте третий экран: Ctrl+A Ctrl+C и в нём запустите операцию поиска. После этого вы можете перемещаться по экранам, пользуясь комбинациями клавиш Ctrl+A 0, Ctrl+A 1 и Ctrl+A 2 соответственно.

Но самой интересной особенностью программы screen является возможность "замораживания" экрана, позволяющая выйти из системы с сохранением состояния сеанса и войти в систему с другого компьютера с полным восстановлением ранее сохранённого состояния.

Обычно выход из программы screen происходит, когда завершается выполнение каждого экземпляра командной оболочки по отдельности или при помощи комбинаций клавиш Ctrl+A Ctrl+\ одновременно уничтожаются все текущие экземпляры. Если необходимо прервать сеанс screen с возможностью его продолжения, то воспользуйтесь клавишными комбинациями Ctrl+A Ctrl+D. На экране появится сообщение о прерывании работы программы и "отключении" от данного сеанса:

$ ^A^D
[detached]
$

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

screen -r

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

Если у вас имеется возможность доступа к своему рабочему компьютеру в офисе с домашнего компьютера (например, через ssh), то вы можете по окончании работы сохранить screen-сеанс, а придя домой, возобновить прерванную работу.

4. Заключение

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

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


Ресурсы для скачивания


Комментарии

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

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Linux
ArticleID=495297
ArticleTitle=Планирование и автоматизация выполнения заданий средствами командной оболочки shell: Часть 1. Простейшие средства
publish-date=06102010