Главная страница

вцуйф ауцй. Bash скрипты


Скачать 3.58 Mb.
НазваниеBash скрипты
Анкорвцуйф ауцй
Дата15.08.2022
Размер3.58 Mb.
Формат файлаpdf
Имя файлаbash.pdf
ТипРуководство
#646431
страница5 из 6
1   2   3   4   5   6
Подсчёт количества файлов Напишем скрипт, который подсчитывает файлы, находящиеся в директориях, которые записаны в переменную окружения PATH. Для того, чтобы это сделать, понадобится, для начала, сформировать список путей к директориям. Сделаем это с помощью sed, заменив двоеточия на пробелы
$ echo $PATH | sed 's/:/ /g' Команда замены поддерживает регулярные выражения в качестве шаблонов для поиска текста. В данном случае всё предельно просто, ищем мы символ двоеточия, но никто не мешает использовать здесь и что-нибудь другое — всё зависит от конкретной задачи. Теперь надо пройтись по полученному списку в цикле и выполнить там необходимые для подсчёта количества файлов действия. Общая схема скрипта будет такой mypath=$(echo $PATH | sed 's/:/ /g') for directory in $mypath do done Теперь напишем полный текст скрипта, воспользовавшись командой ls для получения сведений о количестве файлов в каждой из директорий
#!/bin/bash mypath=$(echo $PATH | sed 's/:/ /g') count=0 for directory in $mypath do check=$(ls $directory) for item in $check do count=$[ $count + 1 ] done echo "$directory - $count"

123 count=0 done При запуске скрипта может оказаться, что некоторых директорий из PATH не существует, однако, это не помешает ему посчитать файлы в существующих директориях.
Подсчёт файлов Главная ценность этого примера заключается в том, что пользуясь тем же подходом, можно решать и куда более сложные задачи. Какие именно — зависит от ваших потребностей. Проверка адресов электронной почты Существуют веб-сайты с огромными коллекциями регулярных выражений, которые позволяют проверять адреса электронной почты, телефонные номера, итак далее. Однако, одно дело — взять готовое, и совсем другое — создать что-то самому. Поэтому напишем регулярное выражение для проверки адресов электронной почты. Начнём с анализа исходных данных. Вот, например, некий адрес username@hostname.com Имя пользователя, username, может состоять из алфавитно-цифровых и некоторых других символов. А именно, это точка, тире, символ подчёркивания, знак плюс. За именем пользователя следует знак @. Вооружившись этими знаниями, начнём сборку регулярного выражения сего левой части, которая служит для проверки имени пользователя. Вот что у нас получилось
^([a-zA-Z0-9_\-\.\+]+)@ Это регулярное выражение можно прочитать так Вначале строки должен быть как минимум один символ из тех, которые имеются в группе, заданной в квадратных скобках, а после этого должен идти знак @». Теперь — очередь имени хоста — hostname. Тут применимы те же правила, что и для имени пользователя, поэтому шаблон для него будет выглядеть так
([a-zA-Z0-9_\-\.]+) Имя домена верхнего уровня подчиняется особым правилам. Тут могут быть лишь алфавитные символы, которых должно быть не меньше двух (например, такие домены обычно содержат код страны, и не больше пяти. Всё это значит, что шаблон для проверки последней части адреса будет таким
\.([a-zA-Z]{2,5})$

124 Прочесть его можно так Сначала должна быть точка, потом — от 2 до 5 алфавитных символов, а после этого строка заканчивается. Подготовив шаблоны для отдельных частей регулярного выражения, соберём их вместе
^([a-zA-Z0-9_\-\.\+]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$ Теперь осталось лишь протестировать то, что получилось
$ echo "name@host.com" | awk '/^([a-zA-Z0-9_\-\.\+]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-
Z]{2,5})$/{print $0}'
$ echo "name@host.com.us" | awk '/^([a-zA-Z0-9_\-\.\+]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-
Z]{2,5})$/{print $0}' Проверка адреса электронной почты с помощью регулярных выражений То, что переданный awk текст выводится на экран, означает, что система распознала в нём адрес электронной почты. Итоги Если регулярное выражение для проверки адресов электронной почты, которое встретилось вам в самом начале статьи, казалось тогда совершенно непонятным, надеемся, сейчас оно уже не выглядит бессмысленным набором символов. Если это действительно так — значит данный материал выполнил своё предназначение. На самом деле, регулярные выражения — это тема, которой можно заниматься всю жизнь, но даже то немногое, что мы разобрали, уже способно помочь вам в написании скриптов, которые довольно продвинуто обрабатывают тексты. В этой серии материалов мы обычно показывали очень простые примеры скриптов, которые состояли буквально из нескольких строк. В следующий раз рассмотрим кое-что более масштабное.

125 скрипты, часть 10: практические примеры В предыдущих материалах мы обсуждали различные аспекты разработки скриптов, говорили о полезных инструментах, но до сих пор рассматривали лишь небольшие фрагменты кода. Пришло время более масштабных проектов. А именно, здесь вы найдёте два примера. Первый — скрипт для отправки сообщений, второй пример — скрипт, выводящий сведения об использовании дискового пространства. Главная ценность этих примеров для тех, кто изучает bash, заключается в методике разработки. Когда перед программистом встаёт задача по автоматизации чего бы тони было, его путь редко бывает прямыми быстрым. Задачу надо разбить на части, найти средства решения каждой из подзадача потом собрать из частей готовое решение. Отправка сообщений в терминал пользователя В наши дни редко кто прибегает к одной из возможностей Linux, которая позволяет общаться, отправляя сообщения в терминалы пользователей, вошедших в систему. Сама по себе команда отправки сообщений, write, довольно проста. Для того, чтобы ей воспользоваться, достаточно знать имя пользователя и имя его терминала. Однако, для успешной отправки сообщения, помимо актуальных данных о пользователе и терминале, надо знать, вошёл ли пользователь в систему, не запретил ли он запись в свой терминал. В результате, перед отправкой сообщения нужно выполнить несколько проверок. Как видите, задача отправить сообщение, при ближайшем рассмотрении, оказалась задачей проверить возможность отправки сообщения, и, если нет препятствий, отправить его. Займёмся решением задачи, то есть — разработкой скрипта. Команды who и mesg Ядром скрипта являются несколько команд, которые мы ещё не обсуждали. Всё остальное должно быть вам знакомо по предыдущим материалам. Первое, что нам тут понадобится — команда who. Она позволяет узнать сведения о пользователях, работающих в системе. В простейшем виде её вызов выглядит так
$ who Результаты вызова команды who В каждой строчке, которую выводит команда who, нас интересуют первых два показателя — имя пользователя и сведения о его терминале. По умолчанию запись в терминал разрешена, но пользователь может, с помощью команды mesg, запретить отправку ему сообщений. Таким образом, прежде чем пытаться что-то кому-то отправить, неплохо будет проверить, разрешена ли отправка сообщений. Если нужно узнать собственный статус, достаточно ввести команду mesg без параметров

126
$ mesg Команда mesg В данном случае команда вывела «is y», это значит, что пользователь, под которым мы работаем в системе, может принимать сообщения, отправленные в его терминал. В противном случае mesg выведет «is n». Для проверки того, разрешена ли отправка сообщений какому-то другому пользователю, можно использовать уже знакомую вам команду who с ключом -T:
$ who -T При этом проверка возможна только для пользователей, которые вошли в систему. Если такая команда, после имени пользователя, выведет чёрточку (-), это означает, что пользователь запретил запись в свой терминал, то есть, сообщения ему отправлять нельзя. О том, что пользователю можно отправлять сообщения, говорит знак плюс (+). Если у вас приём сообщений отключён, а вы хотите позволить другим пользователям отправлять вам сообщения, можно воспользоваться такой командой
$ mesg y Включение приёма сообщений от других пользователей После включения приёма сообщений mesg возвращает «is y». Конечно, для обмена сообщениями нужны два пользователя, поэтому мы, после обычного входа в систему, подключились к компьютеру по ssh. Теперь можно поэкспериментировать. Команда write Основной инструмент для обмена сообщениями между пользователями, вошедшими в систему — команда write. Если приём сообщений у пользователя разрешён, с помощью этой команды ему можно отправлять сообщения, используя его имя и сведения о терминале. Обратите внимание на то, что с помощью write можно отправлять сообщения пользователям, вошедшим в виртуальную консоль. Пользователи, которые работают в графическом окружении (KDE,
Gnome, Cinnamon, итак далее, не могут получать подобные сообщения. Итак, мы, работая под пользователем likegeeks, инициируем сеанс связи с пользователем testuser, который работает в терминале pts/1, следующим образом
$ write testuser pts/1

127 Проверка возможности отправки сообщений и отправка сообщения После выполнения вышеуказанной команды перед нами окажется пустая строка, в которую нужно ввести первую строку сообщения. Нажав клавишу ENTER, мы можем ввести следующую строку сообщения. После того, как ввод текста завершён, окончить сеанс связи можно, воспользовавшись комбинацией клавиш CTRL + D, которая позволяет ввести символ конца файла
Вот что увидит в своём терминале пользователь, которому мы отправили сообщение. Новое сообщение, пришедшее в терминал Получатель может понять от кого пришло сообщение, увидеть время, когда оно было отправлено. Обратите внимание на признак конца файла, EOF, расположенный в нижней части окна терминала. Он указывает на окончание текста сообщения. Полагаем, теперь у насесть всё необходимое для того, чтобы автоматизировать отправку сообщений с помощью сценария командной строки. Создание скрипта для отправки сообщений Прежде чем заниматься отправкой сообщений, нужно определить, вошёл ли интересующий нас пользователь в систему. Сделать это можно с помощью такой команды logged_on=$(who | grep -i -m 1 $1 | awk '{print $1}') Здесь результаты работы команды who передаются команде grep. Ключ -i этой команды позволяет игнорировать регистр символов. Ключ -m 1 включён в вызов команды на тот случай, если пользователь вошёл в систему несколько раз. Эта команда либо не выведет ничего, либо выведет имя пользователя его мы укажем при вызове скрипта, оно попадёт в позиционную переменную $1), соответствующее первому найденному сеансу. Вывод grep мы передаём awk. Эта команда, опять же, либо не выведет ничего, либо выведет элемент, записанный в собственную переменную $1, то есть — имя пользователя. В итоге то, что получилось, попадает в переменную logged_on. Теперь надо проверить переменную logged_on, посмотреть, есть ливней что-нибудь: if [ -z $logged_on ] then echo "$1 is not logged on." echo "Exit"

128 exit fi Если вы не вполне уверенно чувствуете себя, работая с конструкцией if, взгляните на этот материал. Скрипт, содержащий вышеописанный код, сохраним в файле senderscript и вызовем, передав ему, в качестве параметра командной строки, имя пользователя testuser. Проверка статуса пользователя Тут мы проверяем, является ли logged_on переменной с нулевой длиной. Если это так, нам сообщат о том, что в данный момент пользователь в систему не вошли скрипт завершит работу с помощью команды exit. В противном случае выполнение скрипта продолжится. Проверка возможности записи в терминал пользователя Теперь надо проверить, принимает ли пользователь сообщения. Для этого понадобится такая конструкция, похожая на ту, которую мы использовали выше allowed=$(who -T | grep -i -m 1 $1 | awk '{print $2}') if [ $allowed != "+" ] then echo "$1 does not allowing messaging." echo "Exit" exit fi Проверка возможности отправки сообщений пользователю Сначала мы вызываем команду who с ключом -T. В строке сведений о пользователе, который может принимать сообщения, окажется знак плюс (+), если же пользователь принимать сообщения не может — там будет чёрточка (-). То, что получилось после вызова who, передаётся grep, а потом — awk, формируя переменную allowed.

129 Далее, используя условный оператор, мы проверяем то, что оказалось в переменной allowed. Если знака плюс в ней нет, сообщим о том, что отправка сообщений пользователю запрещена и завершим работу. В противном случае выполнение сценария продолжится. Проверка правильности вызова скрипта Первым параметром скрипта является имя пользователя, которому мы хотим отправить сообщение. Вторым — текст сообщения, в данном случае — состоящий из одного слова. Для того, чтобы проверить, передано ли скрипту сообщение для отправки, воспользуемся таким кодом if [ -z $2 ] then echo "No message parameter included." echo "Exit" exit fi Проверка параметров командной строки, указанных при вызове скрипта Тут, если при вызове скрипта ему не было передано сообщение для отправки, мы сообщаем об этом и завершаем работу. В противном случае — идём дальше. Получение сведений о терминале пользователя Прежде чем отправить пользователю сообщение, нужно получить сведения о терминале, в котором он работает и сохранить имя терминала в переменной. Делается это так terminal=$(who | grep -i -m 1 $1 | awk '{print $2}') Теперь, после того, как все необходимые данные собраны, осталось лишь отправить сообщение echo $2 | write $logged_on $terminal Вызов готового скрипта выглядит так
$ ./senderscript testuser welcome

130 Успешная отправка сообщения с помощью скрипта Как видно, всё работает как надо. Однако, с помощью такого сценария можно отправлять лишь сообщения, состоящие из одного слова. Хорошо бы получить возможность отправлять более длинные сообщения. Отправка длинных сообщений Попробуем вызвать сценарий senderscript, передав ему сообщение, состоящее из нескольких слов
$ ./senderscript likegeeks welcome to shell scripting Попытка отправки длинного сообщения Как видно, отправлено было лишь первое слово. Всё дело в том, что каждое слово сообщения воспринимается внутри скрипта как отдельная позиционная переменная. Для того, чтобы получить возможность отправки длинных сообщений, обработаем параметры командной строки, переданные сценарию, воспользовавшись командой shift и циклом while. shift while [ -n "$1" ] do whole_message=$whole_message' '$1 shift done После этого, в команде отправки сообщения, воспользуемся, вместо применяемой ранее позиционной переменной $2, переменной whole_message: echo $whole_message | write $logged_on $terminal

131 Вот полный текст сценария
#!/bin/bash logged_on=$(who | grep -i -m 1 $1 | awk '{print $1}') if [ -z $logged_on ] then echo "$1 is not logged on." echo "Exit" exit fi allowed=$(who -T | grep -i -m 1 $1 | awk '{print $2}') if [ $allowed != "+" ] then echo "$1 does not allowing messaging." echo "Exit" exit fi if [ -z $2 ] then echo "No message parameter included." echo "Exit" exit fi terminal=$(who | grep -i -m 1 $1 | awk '{print $2}') shift while [ -n "$1" ] do whole_message=$whole_message' '$1 shift done echo $whole_message | write $logged_on $terminal Испытаем его
$ ./senderscript likegeeks welcome to shell scripting

132 Успешная отправка длинного сообщения Длинное сообщение успешно дошло до адресата. Теперь рассмотрим следующий пример. Скрипт для мониторинга дискового пространства Сейчас мы собираемся создать сценарий командной строки, который предназначен для поискав заданных директориях первой десятки папок, на которые приходится больше всего дискового пространства. В этом нам поможет команда du, которая выводит сведения о том, сколько места на диске занимают файлы и папки. По умолчанию она выводит сведения лишь о директориях, с ключом -a в отчёт попадают и отдельные файлы. Её ключ -s позволяет вывести сведения о размерах директорий. Эта команда позволяет, например, узнать объём дискового пространства, который занимают данные некоего пользователя. Вот как выглядит вызов этой команды
$ du -s /var/log/ Для наших целей лучше подойдёт ключ -S (заглавная S), так как он позволяет получить сведения как по корневой папке, таки по вложенным вне директориям
$ du -S /var/log/ Вызов команды du с ключами -s и -S Нам нужно найти директории, на которые приходится больше всего дискового пространства, поэтому список, который выдаёт du, надо отсортировать, воспользовавшись командой sort:
$ du -S /var/log/ | sort -rn

133 Отсортированный список объектов Ключ -n указывает команде на то, что нужна числовая сортировка, ключ -r — на обратный порядок сортировки (самое большое число окажется вначале списка. Полученные данные вполне подходят для наших целей. Для того, чтобы ограничить полученный список первыми десятью записями, воспользуемся потоковым редактором sed, который позволит удалить из полученного списка все строки, начиная с одиннадцатой. Следующий шаг — добавить к каждой полученной строке её номер. Тут также поможет sed, а именно — его команда N: sed '{11,$D; =}' | sed 'N; s/\n/ /' |
Приведём полученные данные в порядок, воспользовавшись awk. Передадим awk то, что получилось после обработки данных с помощью sed, применив, как ив других случаях, конвейер, и выведем полученные данные с помощью команды printf: awk '{printf $1 ":" "\t" $2 "\t" $3 "\n"}' Вначале строки выводится её номер, потом идёт двоеточие и знак табуляции, далее — объём дискового пространства, следом — ещё один знак табуляции и имя папки. Соберём вместе всё то, о чём мы говорили
$ du -S /var/log/ | sort -rn | sed '{11,$D; =}' | sed 'N; s/\n/ /' | awk '{printf $1 ":" "\t" $2 "\t" $3 "\n"}'

134 Вывод сведений о дисковом пространстве Для того, чтобы повысить эффективность работы скрипта, код которого вы совсем скоро увидите, реализуем возможность получения данных сразу по нескольким директориям. Для этого создадим переменную MY_DIRECTORIES и внесём вне список интересующих нас директорий
MY_DIRECTORIES=”/home /var/log”
Переберём список с помощью цикла for и вызовем вышеописанную последовательность команд для каждого элемента списка. Вот что получилось в результате
#!/bin/bash
MY_DIRECTORIES="/home /var/log" echo "Top Ten Disk Space Usage" for DIR in $MY_DIRECTORIES do echo "The $DIR Directory:" du -S $DIR 2>/dev/null | sort -rn | sed '{11,$D; =}' | sed 'N; s/\n/ /' | awk '{printf $1 ":" "\t" $2 "\t" $3 "\n"}' done exit

135 Получение сведений о нескольких директориях Как видите, скрипт выводит, в виде удобного списка, сведения о директориях, список которых хранится в MY_DIRECTORIES. Команду du в этом скрипте можно вызвать с другими ключами, полученный список объектов вполне можно отфильтровать, в целом — тут открывается широкий простор для самостоятельных экспериментов. В результате, вместо работы со списком папок, можно, например, найти самые большие файлы с расширением .log, или реализовать более сложный алгоритм поиска самых больших или самых маленьких) файлов и папок. Итоги Сегодня мы подробно разобрали пару примеров разработки скриптов. Тут хотелось бы напомнить, что наша главная цель — не в том, чтобы написать скрипт для отправки сообщений с помощью команды write, или сценарий, который помогает в поиске файлов и папок, занимающих много места на диске, а в описании самого процесса разработки. Освоив эти примеры, поэкспериментировав сними, возможно
— дополнив их или полностью переработав, вы научитесь чему-то новому, улучшите свои навыки разработки скриптов. На сегодня это всё. В следующий раз поговорим об автоматизации работы с интерактивными утилитами с помощью expect.

136 скрипты, часть 11: expect и автоматизация интерактивных утилит В прошлый раз мы говорили о методике разработки скриптов. Если же суммировать всё, что мы разобрали в предыдущих десяти материалах, то вы, если начинали читать их, ничего не зная о bash, теперь можете сделать уже довольно много всего полезного. Сегодняшняя тема, заключительная в этой серии материалов, посвящена автоматизации работы с интерактивными утилитами, например, со скриптами, которые, в процессе выполнения, взаимодействуют с пользователем. В этом деле нам поможет expect — инструмент, основанный на языке Tcl.
Expect позволяет создавать программы, ожидающие вопросов от других программ и дающие им ответы. Expect можно сравнить с роботом, который способен заменить пользователя при взаимодействии со сценариями командной строки. Основы expect Если expect в вашей системе не установлен, исправить это, например, в Ubuntu, можно так
$ apt-get install expect В чём-то вроде CentOs установка выполняется такой командой
$ yum install expect
Expect предоставляет набор команд, позволяющих взаимодействовать с утилитами командной строки. Вот его основные команды
● spawn — запуск процесса или программы. Например, это может быть командная оболочка,
FTP
,
Telnet, ssh, scp итак далее.
● expect — ожидание данных, выводимых программой. При написании скрипта можно указать, какого именно вывода он ждёт и как на него нужно реагировать.
● send — отправка ответа. скрипт с помощью этой команды может отправлять входные данные автоматизируемой программе. Она похожа на знакомую вам команду echo в обычных bash- скриптах.
● interact — позволяет переключиться наручной режим управления программой. Автоматизация скрипта Напишем скрипт, который взаимодействует с пользователем и автоматизируем его с помощью expect. Вот код скрипта questions:
#!/bin/bash echo "Hello, who are you?" read $REPLY echo "Can I ask you some questions?" read $REPLY echo "What is your favorite topic?"

137 read $REPLY Теперь напишем скрипт, который запустит скрипт questions и будет отвечать на его вопросы
#!/usr/bin/expect -f set timeout -1 spawn ./questions expect "Hello, who are you?\r" send -- "Im Adam\r" expect "Can I ask you some questions?\r" send -- "Sure\r" expect "What is your favorite topic?\r" send -- "Technology\r" expect eof Сохраним скрипт, дав ему имя answerbot. Вначале скрипта находится строка идентификации, которая, в данном случае, содержит путь к expect, так как интерпретировать скрипт будет именно expect. Во второй строке мы отключаем тайм-аут, устанавливая переменную expect timeout в значение -1. Остальной код — это и есть автоматизация работы с скриптом. Сначала, с помощью команды spawn, мы запускаем скрипт. Естественно, тут может быть вызвана любая другая утилита командной строки. Далее задана последовательность вопросов, поступающих от bash- скрипта, и ответов, которые даёт на них expect. Получив вопрос от подпроцесса, expect выдаёт ему заданный ответ и ожидает следующего вопроса. В последней команде expect ожидает признака конца файла, скрипт, дойдя до этой команды, завершается. Теперь пришло время всё это опробовать. Сделаем answerbot исполняемым файлом
$ chmod +x ./answerbot И вызовем его
$./answerbot скрипт отвечает на вопросы скрипта


138 Как видно, скрипт верно ответил на вопросы скрипта. Если на данном этапе вы столкнулись с ошибкой, вызванной тем, что неправильно указано расположение expect, выяснить его адрес можно так
$ which expect Обратите внимание на то, что после запуска скрипта answerbot всё происходит в полностью автоматическом режиме. Тоже самое можно проделать для любой утилиты командной строки. Тут надо отметить, что наш скрипт устроен очень просто, мы точно знаем, какие именно данные он выводит, поэтому написать скрипт для взаимодействия с ним несложно. Задача усложняется при работе с программами, которые написаны другими разработчиками. Однако, здесь на помощь приходит средство для автоматизированного создания скриптов.
1   2   3   4   5   6


написать администратору сайта