К счастью, некоторые из этих несоответствий в данном конкретном сценарии можно обойти, использовав флаг 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
# Теперь нужно создать список числовых идентификаторов процессов,
#·· соответствующих заданному устройству TTY, пользователю или текущему
#·· пользователю.
if [! -z "$tty"]; then
elif [! -z "$user"]; then
else
fi
# Нет совпадений? Тогда все просто!
if [-z "$pids"]; then
··echo "$0: no processes match pattern $1" >&2
··exit 1