qwerty

iplogger.ru - IP Logging Service

четверг, 31 января 2019 г.

Несколько полезных команд для работающих в терминале Linux

Загрузка файла по ссылке с возможностью продолжить загрузку, например, при обрыве соединения:
wget -c http://link/file

Просмотр записи в текстовый файл в реальном времени:
tailf file

Узнать время выполнения команды:
time command

Слежение за изменениями в выводе команды:
watch command

Сочетание клавиш для закрытия текущей сессии в bash и различных утилитах, например клиент MySQL:
Ctrl-D

Быстрое создание резервной копии файла:
cp file{,.copy}

Очистка файла:
> file

Очистка файла при отсутствии прав на файл:
echo -n | sudo tee file

или
sudo truncate -s 0 file

Сочетание клавиш для поиска по истории введенных ранее команд:
Ctrl-R

Копирование файла с выводом прогресса:
pv sourcefile > destfile

Поиск по запущенным процессам без вывода самого процесса поиска:
ps aux | grep [p]rocess

Создание директории и всех вложенных директорий, если они отсутствуют:
mkdir -p /path/to/directory

Вывод всплывающих сообщений в Gnome и Debian-based системах:
notify-send "message!"

Работает аналогично команде cat, с тем отличием, что zcat предназначена для запакованных файлов.
zcat file

Рекурсивный поиск файлов, содержащих искомую строку:
grep -lr string /directory

Выводит список библиотек, необходимых для работы программы:
ldd file

среда, 30 января 2019 г.

Bash-скрипты, часть 11: expect и автоматизация интерактивных утилит

В прошлый раз мы говорили о методике разработки bash-скриптов. Если же суммировать всё, что мы разобрали в предыдущих десяти материалах, то вы, если начинали читать их, ничего не зная о bash, теперь можете сделать уже довольно много всего полезного.



Сегодняшняя тема, заключительная в этой серии материалов, посвящена автоматизации работы с интерактивными утилитами, например, со скриптами, которые, в процессе выполнения, взаимодействуют с пользователем. В этом деле нам поможет expect — инструмент, основанный на языке Tcl.

Expect позволяет создавать программы, ожидающие вопросов от других программ и дающие им ответы. Expect можно сравнить с роботом, который способен заменить пользователя при взаимодействии со сценариями командной строки.



Основы expect


Если expect в вашей системе не установлен, исправить это, например, в Ubuntu, можно так:

$ apt-get install expect

В чём-то вроде CentOs установка выполняется такой командой:

$ yum install expect

Expect предоставляет набор команд, позволяющих взаимодействовать с утилитами командной строки. Вот его основные команды:

  • spawn — запуск процесса или программы. Например, это может быть командная оболочка, FTP, Telnet, ssh, scp и так далее.
  • expect — ожидание данных, выводимых программой. При написании скрипта можно указать, какого именно вывода он ждёт и как на него нужно реагировать.
  • send — отправка ответа. Expect-скрипт с помощью этой команды может отправлять входные данные автоматизируемой программе. Она похожа на знакомую вам команду echo в обычных bash-скриптах.
  • interact — позволяет переключиться на «ручной» режим управления программой.

Автоматизация bash-скрипта


Напишем скрипт, который взаимодействует с пользователем и автоматизируем его с помощью expect. Вот код bash-скрипта 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?"
read $REPLY

Теперь напишем expect-скрипт, который запустит скрипт 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. Остальной код — это и есть автоматизация работы с bash-скриптом.

Сначала, с помощью команды spawn, мы запускаем bash-скрипт. Естественно, тут может быть вызвана любая другая утилита командной строки. Далее задана последовательность вопросов, поступающих от bash-скрипта, и ответов, которые даёт на них expect. Получив вопрос от подпроцесса, expect выдаёт ему заданный ответ и ожидает следующего вопроса.

В последней команде expect ожидает признака конца файла, скрипт, дойдя до этой команды, завершается.

Теперь пришло время всё это опробовать. Сделаем answerbot исполняемым файлом:

$ chmod +x ./answerbot

И вызовем его:

$./answerbot


Expect-скрипт отвечает на вопросы bash-скрипта

Как видно, expect-скрипт верно ответил на вопросы bash-скрипта. Если на данном этапе вы столкнулись с ошибкой, вызванной тем, что неправильно указано расположение expect, выяснить его адрес можно так:

$ which expect

Обратите внимание на то, что после запуска скрипта answerbot всё происходит в полностью автоматическом режиме. То же самое можно проделать для любой утилиты командной строки. Тут надо отметить, что наш bash-скрипт устроен очень просто, мы точно знаем, какие именно данные он выводит, поэтому написать expect-скрипт для взаимодействия с ним несложно. Задача усложняется при работе с программами, которые написаны другими разработчиками. Однако, здесь на помощь приходит средство для автоматизированного создания expect-скриптов.

Autoexpect — автоматизированное создание expect-скриптов


Autoexpect позволяет запускать программы, которые надо автоматизировать, после чего записывает то, что они выводят, и то, что пользователь вводит, отвечая на их вопросы. Вызовем autoexpect, передав этой утилите имя нашего скрипта:

$ autoexpect ./questions

В этом режиме взаимодействие с bash-скриптом ничем не отличается от обычного: мы сами вводим ответы на его вопросы.


Запуск bash-скрипта с помощью autoexpect

После завершения работы с bash-скриптом, autoexpect сообщит о том, что собранные данные записаны в файл script.exp. Взглянем на этот файл.


Файл script.exp

В целом, за исключением некоторых деталей, перед нами такой же скрипт, который мы писали самостоятельно. Если запустить этот скрипт, результат будет тем же.


Запуск expect-скрипта, созданного автоматически

При записи сеансов взаимодействия с некоторыми программами, вроде FTP-клиентов, вы можете столкнуться с тем, что они используют в выводимых данных сведения о времени проведения операции, или выводят данные, отражающие процесс выполнения неких продолжительных действий. В целом, речь идёт о том, что вывод программы при каждом её запуске, правильно воспринимаемый человеком и вызывающий ввод одних и тех же ответов, будет, в тех же условиях, выглядеть по-новому для expect.

Если в expect-скрипте строки, ожидаемые от такой программы, будут жёстко зафиксированы, такой скрипт не сможет нормально работать. Справиться с этим можно, либо удалив из expect-скрипта данные, которые выглядят по-новому при каждом запуске программы, либо использовав шаблоны, пользуясь которыми, expect сможет правильно понять то, что хочет от него программа.

Как видите, autoexpect — это весьма полезный инструмент, но и он не лишён недостатков, исправить которые можно только вручную. Поэтому продолжим осваивать язык expect-скриптов.

Работа с переменными и параметрами командной строки


Для объявления переменных в expect-скриптах используется команда set. Например, для того, чтобы присвоить значение 5 переменной VAR1, используется следующая конструкция:

set VAR1 5

Для доступа к значению переменной перед её именем надо добавить знак доллара — $. В нашем случае это будет выглядеть как $VAR1.

Для того, чтобы получить доступ к аргументам командной строки, с которыми вызван expect-скрипт, можно поступить так:

set VAR [lindex $argv 0]

Тут мы объявляем переменную VAR и записываем в неё указатель на первый аргумент командной строки, $argv 0.

Для целей обновлённого expect-скрипта мы собираемся записать значение первого аргумента, представляющее собой имя пользователя, которое будет использовано в программе, в переменную my_name. Второй аргумент, символизирующий то, что пользователю нравится, попадёт в переменную my_favorite. В результате объявление переменных будет выглядеть так:

set my_name [lindex $argv 0]
set my_favorite [lindex $argv 1]

Отредактируем скрипт answerbot, приведя его к такому виду:

#!/usr/bin/expect -f
set my_name [lindex $argv 0]
set my_favorite [lindex $argv 1]
set timeout -1
spawn ./questions
expect "Hello, who are you?\r"
send -- "Im $my_name\r"
expect "Can I ask you some questions?\r"
send -- "Sure\r"
expect "What is your favorite topic?\r"
send -- "$my_favorite\r"
expect eof

Запустим его, передав в качестве первого параметра SomeName, в качестве второго — Programming:

$ ./answerbot SomeName Programming


Expect-скрипт, использующий переменные и параметры командной строки

Как видите, всё работает так, как ожидалось. Теперь expect-скрипт отвечает на вопросы bash-скрипта, пользуясь переданными ему параметрами командной строки.

Ответы на разные вопросы, которые могут появиться в одном и том же месте


Если автоматизируемая программа может, в одной ситуации, выдать одну строку, а в другой, в том же самом месте — другую, в expect можно использовать блоки, заключённые в фигурные скобки и содержащие варианты реакции скрипта на разные данные, полученные от программы. Выглядит это так:

expect {
    "something" { send -- "send this\r" }
    "*another" { send -- "send another\r" }
}

Здесь, если expect-скрипт увидит строку «something», он отправит ответ «send this». Если же это будет некая строка, оканчивающаяся на «another», он отправит ответ «send another».

Напишем новый скрипт, записав его в файл questions, случайным образом задающий в одном и том же месте разные вопросы:

#!/bin/bash
let number=$RANDOM
if [ $number -gt 25000 ]
then
echo "What is your favorite topic?"
else
echo "What is your favorite movie?"
fi
read $REPLY

Тут мы генерируем случайное число при каждом запуске скрипта, и, проанализировав его, выводим один из двух вопросов.

Для автоматизации такого скрипта нам и пригодится вышеописанная конструкция:

#!/usr/bin/expect -f
set timeout -1
spawn ./questions
expect {
    "*topic?" { send -- "Programming\r" }
    "*movie?" { send -- "Star wars\r" }
}


Ответы на разные вопросы, появляющиеся в одном и том же месте

Как видно, когда автоматизированный скрипт выводит строку, оканчивающуюся на «topic?», expect-скрипт передаёт ему строку «Programming». Получив в том же месте, при другом запуске программы, вопрос, оканчивающийся на «movie?», expect-скрипт отвечает: «Star wars». Это очень полезная техника.

Условный оператор


Expect поддерживает условный оператор if-else и другие управляющие конструкции. Вот пример использования условного оператора:

#!/usr/bin/expect -f
set TOTAL 1
if { $TOTAL < 5 } {
puts "\nTOTAL is less than 5\n"
} elseif { $TOTAL > 5 } {
puts "\nTOTAL greater than 5\n"
} else {
puts "\nTOTAL is equal to 5\n"
}
expect eof


Условный оператор в expect

Тут мы присваиваем переменной TOTAL некое число, после чего проверяем его и выводим текст, зависящий от результата проверки.

Обратите внимание на конфигурацию фигурных скобок. Очередная открывающая скобка должна быть расположена на той же строке, что и предыдущие конструкции.

Цикл while


Циклы while в expect очень похожи на те, что используются в обычных bash-скриптах, но, опять же, тут применяются фигурные скобки:

#!/usr/bin/expect -f
set COUNT 0
while { $COUNT <= 5 } {
puts "\nCOUNT is currently at $COUNT"
set COUNT [ expr $COUNT + 1 ]
}
puts ""


Цикл while в expect

Цикл for


Цикл for в expect устроен по-особому. В начале цикла, в самостоятельных парах фигурных скобок, надо указать переменную-счётчик, условие прекращения цикла и правило модификации счётчика. Затем, опять же в фигурных скобках, идёт тело цикла:

#!/usr/bin/expect -f
for {set COUNT 0} {$COUNT <= 5} {incr COUNT} {
puts "\nCOUNT is at $COUNT"
}
puts ""


Цикл for в expect

Объявление и использование функций


Expect позволяет программисту объявлять функции, используя ключевое слово proc:

proc myfunc { MY_COUNT } {
set MY_COUNT [expr $MY_COUNT + 1]
return "$MY_COUNT"
}

Вот как выглядит expect-скрипт, в котором используется объявленная в нём же функция:

#!/usr/bin/expect -f

proc myfunc { MY_COUNT } {
set MY_COUNT [expr $MY_COUNT + 1]
return "$MY_COUNT"
}

set COUNT 0
while {$COUNT <= 5} {
puts "\nCOUNT is currently at $COUNT"
set COUNT [myfunc $COUNT]
}
puts ""


Функции в expect

Команда interact


Случается так, что автоматизируемые с помощью expect программы требуют ввода конфиденциальных данных, вроде паролей, которые вам не хотелось бы хранить в виде обычного текста в коде скрипта. В подобной ситуации можно воспользоваться командой interact, которая позволит вам, автоматизировав некую часть взаимодействия с программой, самостоятельно ввести, скажем, пароль, а потом опять передать управление expect.

Когда выполняется эта команда, expect-скрипт переключается на чтение ответа на вопрос программы с клавиатуры, вместо того, чтобы передавать ей ранее записанные в нём данные.

Вот bash-скрипт, в общем-то, точно такой же, как мы рассматривали ранее, но теперь ожидающий ввод пароля в ответ на один из своих вопросов:

#!/bin/bash
echo "Hello, who are you?"
read $REPLY
echo "What is you password?"
read $REPLY
echo "What is your favorite topic?"
read $REPLY

Напишем expect-скрипт, который, когда ему предлагают предоставить пароль, передаёт управление нам:

#!/usr/bin/expect -f
set timeout -1
spawn ./questions
expect "Hello, who are you?\r"
send -- "Hi Im Adam\r"
expect "*password?\r"
interact ++ return
send "\r"
expect "*topic?\r"
send -- "Technology\r"
expect eof


Команда interact в expect-скрипте

Встретив команду interact, expect-скрипт остановится, предоставив нам возможность ввести пароль. После ввода пароля надо ввести «++» и expect-скрипт продолжит работу, снова получив управление.

Итоги


Возможностями expect можно пользоваться в программах, написанных на разных языках программирования благодаря соответствующим библиотекам. Среди этих языков — C#, Java, Perl, Python, Ruby, и другие. То, что expect доступен для разных сред разработки — далеко не случайность. Всё дело в том, что это действительно важный и полезный инструмент, который используют для решения множества задач. Здесь и проверка качества ПО, и выполнение различных работ по сетевому администрированию, автоматизация передачи файлов, автоматическая установка обновлений и многое другое.

Освоив этот материал, вы ознакомились с основными концепциями expect и научились пользоваться инструментом autoexpect для автоматического формирования скриптов. Теперь вы вполне можете продолжить изучение expect, воспользовавшись дополнительными источниками. Вот — сборникучебных и справочных материалов. Вот — достойная внимания серия из трёх статей (123). А вот — официальная страница expect, на которой можно найти ссылки на исходный код программы и список публикаций.

На этом мы завершаем серию материалов о bash-скриптах. Надеемся, её одиннадцать частей, а также бессчётное число комментариев к ним, помогли в достижении цели тем, кто хотел научиться писать сценарии командной строки.

Bash-скрипты, часть 10: практические примеры

В предыдущих материалах мы обсуждали различные аспекты разработки bash-скриптов, говорили о полезных инструментах, но до сих пор рассматривали лишь небольшие фрагменты кода. Пришло время более масштабных проектов. А именно, здесь вы найдёте два примера. Первый — скрипт для отправки сообщений, второй пример — скрипт, выводящий сведения об использовании дискового пространства.



Главная ценность этих примеров для тех, кто изучает bash, заключается в методике разработки. Когда перед программистом встаёт задача по автоматизации чего бы то ни было, его путь редко бывает прямым и быстрым. Задачу надо разбить на части, найти средства решения каждой из подзадач, а потом собрать из частей готовое решение.



Отправка сообщений в терминал пользователя


В наши дни редко кто прибегает к одной из возможностей Linux, которая позволяет общаться, отправляя сообщения в терминалы пользователей, вошедших в систему. Сама по себе команда отправки сообщений, write, довольно проста. Для того, чтобы ей воспользоваться, достаточно знать имя пользователя и имя его терминала. Однако, для успешной отправки сообщения, помимо актуальных данных о пользователе и терминале, надо знать, вошёл ли пользователь в систему, не запретил ли он запись в свой терминал. В результате, перед отправкой сообщения нужно выполнить несколько проверок.

Как видите, задача: «отправить сообщение», при ближайшем рассмотрении, оказалась задачей: «проверить возможность отправки сообщения, и, если нет препятствий, отправить его». Займёмся решением задачи, то есть — разработкой bash-скрипта.

▍Команды who и mesg


Ядром скрипта являются несколько команд, которые мы ещё не обсуждали. Всё остальное должно быть вам знакомо по предыдущим материалам.

Первое, что нам тут понадобится — команда who. Она позволяет узнать сведения о пользователях, работающих в системе. В простейшем виде её вызов выглядит так:

$ who


Результаты вызова команды who

В каждой строчке, которую выводит команда who, нас интересуют первых два показателя — имя пользователя и сведения о его терминале.

По умолчанию запись в терминал разрешена, но пользователь может, с помощью команды mesg, запретить отправку ему сообщений. Таким образом, прежде чем пытаться что-то кому-то отправить, неплохо будет проверить, разрешена ли отправка сообщений. Если нужно узнать собственный статус, достаточно ввести команду mesg без параметров:

$ 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


Проверка возможности отправки сообщений и отправка сообщения

После выполнения вышеуказанной команды перед нами окажется пустая строка, в которую нужно ввести первую строку сообщения. Нажав клавишу 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"
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.

Далее, используя условный оператор, мы проверяем то, что оказалось в переменной 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


Успешная отправка сообщения с помощью bash-скрипта

Как видно, всё работает как надо. Однако, с помощью такого сценария можно отправлять лишь сообщения, состоящие из одного слова. Хорошо бы получить возможность отправлять более длинные сообщения.

▍Отправка длинных сообщений


Попробуем вызвать сценарий 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

Вот полный текст сценария:

#!/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


Успешная отправка длинного сообщения:

Длинное сообщение успешно дошло до адресата. Теперь рассмотрим следующий пример.

Скрипт для мониторинга дискового пространства


Сейчас мы собираемся создать сценарий командной строки, который предназначен для поиска в заданных директориях первой десятки папок, на которые приходится больше всего дискового пространства. В этом нам поможет команда du, которая выводит сведения о том, сколько места на диске занимают файлы и папки. По умолчанию она выводит сведения лишь о директориях, с ключом -aв отчёт попадают и отдельные файлы. Её ключ -s позволяет вывести сведения о размерах директорий. Эта команда позволяет, например, узнать объём дискового пространства, который занимают данные некоего пользователя. Вот как выглядит вызов этой команды:

$ du -s /var/log/

Для наших целей лучше подойдёт ключ -S (заглавная S), так как он позволяет получить сведения как по корневой папке, так и по вложенным в неё директориям:

$ du -S /var/log/


Вызов команды du с ключами -s и -S

Нам нужно найти директории, на которые приходится больше всего дискового пространства, поэтому список, который выдаёт du, надо отсортировать, воспользовавшись командой sort:

$ du -S /var/log/ | sort -rn


Отсортированный список объектов

Ключ -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"}'


Вывод сведений о дисковом пространстве

Для того, чтобы повысить эффективность работы скрипта, код которого вы совсем скоро увидите, реализуем возможность получения данных сразу по нескольким директориям. Для этого создадим переменную 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


Получение сведений о нескольких директориях

Как видите, скрипт выводит, в виде удобного списка, сведения о директориях, список которых хранится в MY_DIRECTORIES.

Команду du в этом скрипте можно вызвать с другими ключами, полученный список объектов вполне можно отфильтровать, в целом — тут открывается широкий простор для самостоятельных экспериментов. В результате, вместо работы со списком папок, можно, например, найти самые большие файлы с расширением .log, или реализовать более сложный алгоритм поиска самых больших (или самых маленьких) файлов и папок.

Итоги


Сегодня мы подробно разобрали пару примеров разработки скриптов. Тут хотелось бы напомнить, что наша главная цель — не в том, чтобы написать скрипт для отправки сообщений с помощью команды write, или сценарий, который помогает в поиске файлов и папок, занимающих много места на диске, а в описании самого процесса разработки. Освоив эти примеры, поэкспериментировав с ними, возможно — дополнив их или полностью переработав, вы научитесь чему-то новому, улучшите свои навыки разработки bash-скриптов.

На сегодня это всё. В следующий раз поговорим об автоматизации работы с интерактивными утилитами с помощью expect.

26 полезных приёмов и хитростей Python

Python — один из самых популярных и востребованных языков программирования, —  пишет  tproger.ru. На это есть несколько причин: Его ле...