Дейв Тейлор - Сценарии командной оболочки. Linux, OS X и Unix. 2-е издание
- Название:Сценарии командной оболочки. Linux, OS X и Unix. 2-е издание
- Автор:
- Жанр:
- Издательство:Питер
- Год:2017
- Город:СПб.
- ISBN:978-5-496-03029-8
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Дейв Тейлор - Сценарии командной оболочки. Linux, OS X и Unix. 2-е издание краткое содержание
Цель этой книги — продемонстрировать практические приемы программирования сценариев на bash и познакомить с самыми распространенными утилитами на коротких и компактных примерах, не вдаваясь в излишние подробности. Экспериментируйте с этими сценариями — ломайте, исправляйте и приспосабливайте их под свои нужды, чтобы понять, как они работают. Только так вы сможете решать самые сложные задачи.
Сценарии командной оболочки. Linux, OS X и Unix. 2-е издание - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
··# Так лучше?
··echo "Setting date to $squished. You might need to enter your sudo password: "
··sudo date $squished
··exit 0
Как это работает
Чтобы максимально уменьшить размер сценария, мы использовали функцию eval , решив сразу две задачи. Во-первых, эта строка получает текущие дату и время, используя строку формата команды date. Во-вторых, она записывает полученные значения в переменные nyear, nmon, nday, nhr и nmin, которые затем используются простой функцией askvalue()
, запрашивающей и проверяющей введенные значения. Использование функции eval для присваивания значений переменным также решает любые потенциальные проблемы со сменой дат или другими изменениями, которые могут произойти между вызовами функции askvalue(), что нарушило бы непротиворечивость данных в сценарии. Например, если askvalue получит месяц и день в 23:59:59, а часы и минуты в 0:00:02, системная дата фактически будет установлена на сутки назад — совершенно нежелательный результат.
Нам также нужно гарантировать использование строки с датой правильного формата, потому что, например, в OS X и в Linux он различается. По умолчанию данный сценарий использует формат даты, принятый в OS X, но в строке с комментарием приводится строка с форматом для Linux.
Вот одна из малозаметных проблем, возникающих при работе с командой date. Если в ответ на запросы сценария ввести точное время, а затем потратить несколько мгновений на ввод пароля для sudo, системное время будет на пару секунд отставать от текущего. Возможно, это совсем не проблема, но одна из причин, почему системы, подключенные к сети, должны использовать утилиты NTP (Network Time Protocol — сетевой протокол службы времени) для синхронизации с официальным сервером времени. Знакомство с механизмом синхронизации времени по сети в системах Linux и Unix можно начать с чтения страницы справочного руководства timed(8).
Запуск сценария
Обратите внимание, что сценарий использует команду sudo для вызова команды date с привилегиями root, что наглядно демонстрирует листинг 6.5. Вводя неправильный пароль в ответ на запросы sudo, вы можете экспериментировать со сценарием, не боясь получить неожиданные результаты.
Результаты
Листинг 6.5.Тестирование интерактивного сценария setdate
$ setdate
year [2017]:
month [05]:
day [07]:
hour [16]: 14
minute [53]: 50
Setting date to 201705071450. You might need to enter your sudo password:
passwd:
$
№ 47. Завершение процессов по имени
В Linux и в отдельных версиях Unix имеется удобная команда killall, позволяющая завершать все работающие приложения, имена которых соответствуют заданному шаблону. Это может пригодиться, например, для завершения всех девяти демонов mingetty или даже просто для отправки сигнала SIGHUP демону xinetd, чтобы заставить его перечитать файл конфигурации. В системах, не имеющих команды killall, можно эмулировать ее с помощью сценария командной оболочки, использующего команду ps для идентификации процессов и их завершения отправкой заданного сигнала.
Самую большую сложность в этом сценарии представляют различия в выводе команды ps в разных операционных системах. Например, давайте посмотрим, насколько различаются выводы по умолчанию команды ps в FreeBSD, Red Hat Linux и OS X.
Сначала посмотрим, что выводится в FreeBSD:
BSD $ ps
PID TT··STAT····TIME COMMAND
792··0··Ss·· 0:00.02 −sh (sh)
4468··0··R+·· 0:00.01 ps
Сравните с выводом в Red Hat Linux:
RHL $ ps
··PID TTY········ TIME CMD
8065 pts/4·· 00:00:00 bash
12619 pts/4·· 00:00:00 ps
И, наконец, с выводом в OS X:
OSX $ ps
··PID TTY··········TIME CMD
37055 ttys000·· 0:00.01 −bash
26881 ttys001·· 0:00.08 −bash
Что еще хуже, вместо того чтобы смоделировать типичную Unix-команду ps, GNU-версия команды ps принимает флаги в стиле BSD, в стиле SYSV и в стиле GNU. Полная каша!
К счастью, некоторые из этих несоответствий в данном конкретном сценарии можно обойти, использовав флаг cu, что позволяет получить единообразный вывод, включающий в себя владельца процесса, полное имя команды и — что особенно важно — числовой идентификатор процесса.
Кроме того, данный сценарий — первый, в котором мы по-настоящему используем всю мощь команды getopts, позволяющей работать с самыми разными параметрами командной строки и даже подставлять значения по умолчанию. Сценарий в листинге 6.6 имеет четыре начальных флага, три из которых имеют обязательные аргументы: −s SIGNAL, −u USER, −t TTY и −n. Вы увидите их в первом блоке кода.
Код
Листинг 6.6.Сценарий killall
#!/bin/bash
# killall — посылает указанный сигнал всем процессам, имена которых
#·· соответствуют заданному шаблону.
# По умолчанию завершает только процессы, принадлежащие текущему
#·· пользователю, только если не запущен с привилегиями root.
#·· Используйте −s SIGNAL, чтобы указать сигнал, посылаемый процессам;
#·· −u USER, чтобы указать пользователя; −t TTY, чтобы указать устройство
#·· tty; и −n, чтобы только получить список процессов, которые могли бы
#·· быть завершены, но без их завершения.
signal="-INT"······# Сигнал по умолчанию — прерывание.
user=""·· tty=""·· donothing=0
while getopts "s: u: t: n" opt; do
··case "$opt" in
····# Обратите внимание на хитрый трюк ниже: фактическая команда kill ожидает
····#·· получить имя сигнала в виде −SIGNAL, но сценарий требует
····#·· указать его без дефиса: SIGNAL, поэтому мы просто
····#·· добавляем "-" в начало полученного имени сигнала.
····s) signal="-$OPTARG";;;
····u) if [! -z "$tty"]; then
··········# Логическая ошибка: нельзя одновременно указать пользователя
··········#·· и устройство TTY
··········echo "$0: error: −u and −t are mutually exclusive." >&2
··········exit 1
········fi
········user=$OPTARG;;;
····t) if [! -z "$user"]; then
··········echo "$0: error: −u and −t are mutually exclusive." >&2
··········exit 1
········fi
········tty=$2;;;
····n) donothing=1;;;
····?) echo "Usage: $0 [-s signal] [-u user|-t tty] [-n] pattern" >&2
········exit 1
··esac
done
# Завершить обработку всех начальных флагов с помощью getopts…
shift $(($OPTIND — 1))
# Если пользователь не указал начальных аргументов
#·· (предыдущая проверка в ветке —?)
if [$# −eq 0]; then
··echo "Usage: $0 [-s signal] [-u user|-t tty] [-n] pattern" >&2
··exit 1
fi
# Теперь нужно создать список числовых идентификаторов процессов,
Интервал:
Закладка: