ку, связанную со временем. Имея нашу собственную команду at, мы можем
настроить ее по своему вкусу и изменить ее, когда необходимо. Команда
at, представленная здесь, фактически более гибкая, чем at в системе
Berkeley, хотя в первой отсутствуют некоторые особенности второй. Она
более гибкая потому, что вы можете поместить настоящие команды в фоно-
вую задачу at, в то время как для at в системе Berkeley вы должны
использовать имя командного файла интерпретатора shell. Метод Berkeley
запрещает вам вызывать исполняемые модули непосредственно в командной
строке, а наша at - нет. (Конечно, вы можете с таким же успехом
использовать командные файлы интерпретатора shell, если вам это необ-
ходимо.)
ЧТО ДЕЛАЕТ at?
Команда at дает нам возможность собирать несколько команд в одно
целое и впоследствии запускать их. Когда они выполняются, их вывод мо-
жет либо идти на экран, либо перенаправляться в определенный файл.
Командная строка принимает два параметра: время выполнения и ко-
мандную строку, которую следует выполнить. Время выражено в формате
час:минута. Час должен быть указан строкой из двух цифр (в диапазоне
от 0 до 23 часов), так как его использует команда date. Использование
того же стандарта, что и в команде date, значительно упрощает команду
at. В качестве второго параметра может быть любая команда, которую
обычно можно ввести в командной строке интерпретатора shell. Можно
также использовать конвейеры, составные команды и переназначения. Нет
ограничений на то, какая команда может быть выполнена. Команда at мо-
жет запустить обычный исполняемый модуль UNIX или ваш собственный ко-
мандый файл.
Выход at по умолчанию направляется в стандартный вывод. Стандарт-
ным выводом в данном случае является экран терминала. Команда at в
системе Berkeley не имеет вывода по умолчанию, что несколько затрудня-
ет получение результата и отправку его на экран.
Команда at всегда запускается как фоновая задача. Нецелесообразно
запускать ее в приоритетном режиме, где она блокирует терминал на все
время своего выполнения. Пребывая в фоновом режиме, at освобождает
ресурсы, но все же работает для вас. Между прочим, отметим, что когда
процессы ставятся в фоновый режим изнутри командного файла, идентифи-
катор процесса не печатается на экран, как это происходит, когда про-
цессы запускаются в фоновом режиме с клавиатуры.
Порождение большого количества фоновых процессов может иметь от-
рицательный эффект для системы. Каждая фоновая задача - это цикл while
интерпретатора shell, который работает очень медленно. Когда много фо-
новых процессов, мало времени центрального процессора остается на дру-
гие цели. В результате производительность системы ухудшается. В боль-
ших системах это, вероятно, не проблема, если только система не загру-
жена множеством пользователей, но вы должны использовать это средство
с осторожностью.
Отметим, что формат час:минута годится только для одного полного
дня. Данная программа at задумана как ежедневная и не имеет средств
запуска в определенный день или месяц, хотя вы можете легко расширить
ее, как только поймете, как читается и используется информация о вре-
мени.
ПРИМЕРЫ
1. $ at 11:45 echo ^G^G It's almost lunch time
Без пятнадцати минут двенадцать дважды выдается звуковой сигнал
(control-G) и выводится сообщение о ленче.
2. $ at 10:45 "if [ -s $MAIL ]; then echo ^G You have mail; fi"
Без пятнадцати одиннадцать проверяется, существует ли мой почто-
вый файл и есть ли в нем хотя бы один символ ($MAIL есть
/usr/spool/mail/russ). Если это так, выдается звуковой сигнал и сооб-
щение о том, что у меня есть почта.
3. $ at 17:00 "c; date; banner ' time to' ' go home'"
В пять часов вечера очищается экран (с помощью команды c, описан-
ной далее в данной книге), печатается дата и выводится крупными буква-
ми на весь экран сообщение "time to go home" ("пора домой"). С помощью
апострофов в командной строке banner мы можем добиться вывода символа
возврата каретки, чтобы разместить каждый набор слов в отдельной стро-
ке. Если какая-либо из этих команд не срабатывает (например, не найде-
на команда c), то и весь фоновый процесс оканчивается неудачей.
ПОЯСНЕНИЯ
Прежде всего at проверяет, правильно ли она была вызвана. Строки
4-8 делают проверку ошибок. В командной строке должны присутствовать
по крайней мере два параметра: время и команда. Если это так, то счет-
чик позиционных параметров равен 2. Если этот счетчик меньше 2, прои-
зошла ошибка. В стандартный файл ошибок посылаются сообщения об ошибке
с помощью переадресации в файловый дескриптор 2.
Переменная интерпретатора shell ITS инициализируется в строке 10.
В ней устанавливается значение первого позиционного параметра ($1),
которым является час:минута. Как только мы занесли это значение в пе-
ременную, оно больше не нужно нам в командной строке. Команда shift
удаляет $1 из командной строки. Теперь командная строка состоит из вы-
зывающей команды $0 (т.е. самой at) и остатка строки ($@ или $*). Вы-
зывающая команда не вычисляется как часть остатка строки, поэтому вам
не нужно заботиться об аргументе $0.
Далее at переходит к вечному циклу while в строках 12-21. Вечным
этот цикл делает команда : (двоеточие). Это встроенная команда интерп-
ретатора shell, которая ничего не делает кроме того, что всегда возв-
ращает успешный статус выхода, заставляя тем самым цикл продолжаться.
Команда true интерпретатора shell очень похожа и делает программу бо-
лее наглядной. Мы же используем : вместо true, чтобы сократить издерж-
ки на порождение процесса для каждой итерации цикла. Команда : встрое-
на в сам shell. True, напротив, является внешней командой в каталоге
bin (так же, как ls), она должна быть найдена по файловому пути, вы-
полниться и вернуть значение. Это занимает гораздо больше процессорно-
го времени.
На каждой итерации цикла текущее время сверяется с назначенным
временем, переданным из командной строки. Текущее время извлекается из
команды date в строке 14. Обычно date выдает результат в таком форма-
те:
---------------------------------------------------------------------------
|
| Mon Mar 31 06:54:25 PST 1986
|
|
Поскольку это строка фиксированного размера, мы можем посчитать
номера позиций, в которых размещены час и минута. Данные час:минута
находятся в позициях 12-16. Для получения этих символов мы запускаем
команду date, пропускаем ее результат по конвейеру через cut и выреза-
ем нужные позиции. Весь результат присваивается переменной TIME. Заме-
тим, что поле секунд не используется. Наименьшая единица времени в
этой программе - минута.
Все волшебство данной команды заключено в строках 16-20. Если
время, указанное в командной строке, равно текущему времени (строка
16), вычислить и выполнить остальные аргументы командной строки (стро-
ка 17), затем выйти с успешным нулевым значением (строка 18). Если
время не совпало, немного поспать (строка 19) и повторить все сначала.
Символ & в конце цикла в строке 21 превращает весь цикл while в
фоновый процесс. Как мы можем убедиться, что shell выполняет все свои
команды в фоновом режиме и никакие из них не выполняет в оперативном
режиме? В действительности мы не можем этого сделать. Мы должны пола-
гать, что shell так работает. Поскольку многое при программировании на
shell делается исходя из опыта и интуиции, вам приходится испытывать
многие вещи, чтобы увидеть, как они работают. Периодически shell пре-
подносит сюрпризы и делает нечто совершенно неожиданное.
ИССЛЕДОВАНИЯ
Что бы случилось, если бы вы поставили задание at в фоновый ре-
жим, а затем вышли из системы? Ответ зависит от того, с каким shell вы
работаете. Если у вас Bourne shell, то ввод команды control-D при вы-
ходе из системы прекращает выполнение всех ваших фоновых задач.
Единственный способ оставить в живых фоновые задачи после выхода из
системы - использовать команду nohup ("no hang up" - "не казнить").
Nohup обеспечивает, что все сигналы о прекращении процесса не достига-
ют данного процесса. Не получая сигнал о прекращении выполнения, про-
цесс думает, что вы все еще находитесь в системе. Синтаксис выглядит
так:
nohup at 13:00 echo "back from lunch yet?"
Если вы запускаете Си-shell, все фоновые процессы продолжаются
после вашего выхода из системы. Причина в том, что Си-shell переводит
все свои фоновые задачи в состояние защиты от прекращения выполнения.
Этот процесс автоматический, и его не нужно указывать явно.
Вы, возможно, удивлены тем, что в строке 17 использована команда
"eval $@". Это сформировалось методом проб и ошибок. На начальных эта-
пах разработки at команда "$@" использовалась сама по себе. При са-
мостоятельном применении эта команда означает "выполнить все позицион-
ные параметры". Поскольку это была единственная команда, выполнялась
вся строка позиционных параметров, после чего возникали проблемы.
Использование переназначений и переменных интерпретатора shell сильно
запутывало at.
Для иллюстрации рассмотрим пару примеров. Если мы запускаем at с
командной строкой
at 09:30 echo $HOME
то все вроде бы работает. Сначала раскрывается переменная $HOME, затем
echo печатает ее значение - /usr/russ. Но если мы запускаем командную
строку
at 09:30 echo \$HOME
то переменная не раскрывается и echo фактически печатает $HOME вместо
значения переменной $HOME. Мы избежали этого просто с помощью команды
eval для повторного вычисления командной строки перед ее выполнением.
Существо проблемы в том, что вызывающий интерпретатор shell не раскры-
вает значение переменной, поэтому мы заставляем выполняющийся shell
повторно анализировать командную строку и вычислять все переменные. На
этот раз значения переменных раскрываются, и мы получаем верный конеч-
ный результат.
МОДИФИКАЦИИ
Возможно, вы захотите более подробно рассмотреть интерфейс со
временем. В нынешнем состоянии at воспринимает только время в пределах
от 0 до 23 часов в течение одного дня. Неплохим дополнением было бы
заставить его различать время суток, т.е. 8:30 a.m. (до полудня) или
8:30 p.m. (после полудня). Было бы неплохо также иметь возможность
сказать "через 10 минут сделать то-то и то-то". В этом случае команда
могла бы иметь примерно такой вид:
at -n 10 echo "do in now plus 10 minutes"
где -n было бы текущим временем, а 10 добавлялось бы к нему.
Другой очевидной областью модификации является наделение at воз-
можностью запоминания периодов времени, превышающих сутки. Это может
быть завтрашний день, определенный день или даже определенный месяц.
Работа с определенным месяцем может быть не совсем реальной, поскольку
командный файл, выполняемый в фоновом режиме в течение нескольких
месяцев, потребует громадного количества процессорного времени, а так-
же хранения постоянно возрастающего счетчика идентификаторов про-
цессов, что даст, вероятно, пользователям искаженное представление об
активности системы. По достижении максимального номера процесса, снова
вернутся младшие номера, так что это не приведет к каким -либо серьез-
ным последствиям. Решение вопроса о том, стоит ли такой ценой дости-
гать вашей цели, зависит от того, считаете ли вы, что ваши требования
излишне загружают систему.
---------------------------------------------------------------------------
ИМЯ: b
---------------------------------------------------------------------------
b Обработчик фоновых задач
ФОРМАТ ВЫЗОВА
b any_command_with_options_and_arguments
(любая команда с опциями и аргументами)
ПРИМЕР ВЫЗОВА
b cg f.c
Компилировать исходный файл в фоновом режиме, где cg - командная