Пример скрипта bash
В этом посте я выложил пример скрипта написанного на bash и постарался подробно описать, что, как и почему делалось. На курсах Linux мы уже закончили тему bash и чтобы понять как мы ее усвоили преподаватель дал нам домашнее задание по написанию скрипта на bash. Задание звучало примерно так: “написать службу, которая будет выводить на 8-ю консоль время, в верхнем левом углу, с интервалом в одну секунду”.
Для решения задачи нам потребуется написать два скрипта. Первый скрипт будет выводить информацию на 8-ю консоль, а второй будет скриптом управления запуском-остановкой первого скрипта. Сначала рассмотрим более простой - первый скрипт. Я назвал его showtime.
Вот текст скрипта:
1 2 3 4 5 6 7 8 9 10 11 12 | if [ $(echo &>/dev/null > /dev/tty8; echo $?) -eq 0 ] then while [ 1 -lt 2 ] do clear > /dev/tty8 date +%H:%M:%S > /dev/tty8 sleep 1 done else echo "Служба showtime. Управление через sudo /etc/init.d/timeconsoled start|stop" exit 2 fi |
Теперь комментарии. С первой строкой все понятно - это описание интерпретатора, который будет выполнять скрипт. Вторую строку - if [ $(echo &>/dev/null > /dev/tty8; echo $?) -eq 0 ] - разберем подробнее. Эта строка проверяет имеет ли скрипт доступ к консоли /dev/tty8, чтобы выводить туда информацию. Результат выполнения команд в $( ) сравнивается -eq с цифрой 0.
echo &>/dev/null > /dev/tty8 - пытаемся записать пустую строку в /dev/tty8. Чтобы на текущую консоль не выводились служебные сообщения команды echo (из потока вывода или потока ошибок), то мы перенаправляем их при помощи > в специальное устройство /dev/null (в “никуда”). После выполнения этой команды будет выполнена команда echo $?, которая вернет код результата выполнения последней команды. Если доступ к /dev/tty8, то будет возвращен 0 и скрипт продолжит выполнение перейдя на третью строку then, если писать не можем, то переходим на else (строка 12), затем на команду echo “Служба showtime. Управление через - sudo /etc/init.d/timeconsoled start|stop” (строка 13) и на завершающую команду exit 2 (строка 14). По команде exit 2 скрипт прекратит свою работу и вернет код возврата 2.
Если запись в /dev/tty8 возможна, то после второй строки попадаем на then (строка 3) и далее по порядку.
clear > /dev/tty8 - выполняем очистку консоли, если вдруг там был какая-то информация.
Строки 5, 6 и 11 (while do done) - организация цикла. while [ true ] - позволяет организовать бесконечный цикл, так как true всегда возвращает 0.
echo -en “\r \r” > /dev/tty8 - данная команда будет заменять область где будет выведено время пробелами и возвращать курсор в исходную позицию перед выводом следующего значения времени. Ключ n в команде echo сигнализирует что после вывода информации не нужно переходить на следующую строку. Ключ e - означает, что \r должно интерпретироваться как возврат каретки (курсора) на начало строки. То есть курсор будет возвращен на начало строки, затем будет выведена пустая строка и курсор снова будет возвращен на начало строки в консоли /dev/tty8.
ttt=$(date +%H:%M:%S) - присваиваем переменной ttt текущее значение времени.
echo -n “$ttt” > /dev/tty8 - выводим значение времени на восьмую консоль.
sleep 1 - останавливаем скрипт на одну секунду. Меняя значение можно организовать другой шаг обновления времени на консоли.
С первым скриптом все. Его уже можно попробовать запустить от имени рута и посмотреть выводится ли время на консоль. Не забудьте только сделать скрипт исполняемым: chmod a+x showtime.
1 2 | igor@adm-ubuntu:~/linux$ sudo /usr/sbin/showtime & [1] 12562 |
Переходим ко второму скрипту.
Этот скрипт будет находится в директории /etc/init.d/, где находятся все скрипты управления службами. Данный скрипт будет называться timeconsole, и в качестве параметров будет принимать стандартные start (для запуска) и stop (для остановки).
Текст скрипта timeconsole.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | #!/bin/bash case $1 in start) if [ -z "$(ps ax | grep "/usr/sbin/[s]howtime")" ] then if [ -x /usr/sbin/showtime ] then echo "Запускаем демон..." /usr/sbin/showtime & sleep 1 if [ -n "$(ps ax | grep "/usr/sbin/[s]howtime")" ] then echo "Демон запущен" else echo "Запуск не удался!" exit 1 fi else echo "Исполняемый файл не найден!" fi else echo "Демон с именем /usr/sbin/showtime уже запущен!" fi ;; stop) PID="$(ps ax | grep "/usr/sbin/[s]howtime" | awk '{ print $1 }')" if [ -n "$PID" ] then echo "Останавливаем демон..." kill -15 "$PID" sleep 1 if [ -z "$(ps ax | grep "/usr/sbin/[s]howtime" | awk '{ print $1 }')" ] then echo "Демон остановлен" clear > /dev/tty8 else echo "Остановка не удалась" exit 1 fi else echo "Демон не запущен!" fi ;; *) echo echo "Набирайте $0 start|stop" echo exit 1 ;; esac |
Данный скрипт можно расширять почти до бесконечности всяческими проверками и служебными сообщениями, поэтому пока в таком варианте. Основа скрипта - case который во второй строке проверяет первый параметр передаваемый скрипту во время запуска. Реализована обработка параметров start и stop, а также сообщение-подсказка, если исполняют скрипт без параметра или с другими параметрами. Ничего сложного в данном скрипте (как и в первом) нет, поэтому остановлюсь только на некоторых командах. Если будут еще непонятные моменты, спрашивайте в комментариях - обязательно отвечу.
Строка 4 - if [ -z "$(ps ax | grep "/usr/sbin/[s]howtime”)” ] - здесь идет проверка не запущен ли уже процесс с именем /usr/sbin/showtime. Почему написано “/usr/sbin/[s]howtime”, а не “/usr/sbin/showtime”? Это особенность работы команды grep. Посмотрите на результаты работы обеих вариантов при запущенном процессе showtime:
1 2 3 | igor@adm-ubuntu:~/linux$ ps ax | grep "/usr/sbin/showtime" 13276 pts/0 S 0:00 /bin/bash /usr/sbin/showtime 14375 pts/0 S+ 0:00 grep /usr/sbin/showtime |
1 2 | igor@adm-ubuntu:~/linux$ ps ax | grep "/usr/sbin/[s]howtime" 13276 pts/0 S 0:00 /bin/bash /usr/sbin/showtime |
А вот если процесс showtime не запущен:
1 2 | igor@adm-ubuntu:~/linux$ ps ax | grep "/usr/sbin/showtime" 14375 pts/0 S+ 0:00 grep /usr/sbin/showtime |
1 | igor@adm-ubuntu:~/linux$ ps ax | grep "/usr/sbin/[s]howtime" |
Почему так - распишу в отдельной статье.
Строка 26 - PID=”$(ps ax | grep “/usr/sbin/[s]howtime” | awk ‘{ print $1 }’)” - команда получает PID запущенного процесса /usr/sbin/showtime, который затем будет использован для команды kill (строка 30). О команде awk я упоминал здесь.
Строка 46 - echo “Набирайте $0 start|stop” - $0 - вернет имя скрипта timeconsole в том виде в котором его запускали из консоли.
Для написания данных скриптов достаточно было информации о bash, которую я получил на лекциях посвященных bash, плюс man echo и анализ скриптов находящихся в каталоге /etc/init.d.
Теперь осталось скопировать скрипт showtime в каталог /usr/sbin/, а скрипт timeconsole в каталог /etc/init.d/.
В работе запуск и останов выглядит так:
1 2 3 4 5 6 7 8 9 10 | igor@adm-ubuntu:~/linux$ sudo /etc/init.d/timeconsole start Демон с именем /usr/sbin/showtime уже запущен! igor@adm-ubuntu:~/linux$ sudo /etc/init.d/timeconsole stop Останавливаем демон... Демон остановлен igor@adm-ubuntu:~/linux$ sudo /etc/init.d/timeconsole start Запускаем демон... Демон запущен |
Скрипты писались и проверялись в Ubuntu 9.10
Max:
День добрый.
В скрипте showtime красивше использовать
while true
вместо
while [ 1 -lt 2 ]
Ответить
Igorka Reply:
декабря 4, 2010 at 22:37
Добрый день,
Согласен. Спасибо за подсказку.
Ответить
SchiFFer:
Как насчет заменить
PID=”$(ps ax | grep “/usr/sbin/[s]howtime” | awk ‘{ print $1 }’)”
на
pgrep showtime
? :)
К тому же, внутри скрипта можно вычитывать значение обратными кавычками PID=`pgrep showtime` (передал в переменную для примера, можно и сразу, без транзита :))
Ответить
18 сентября 2012, 16:14