сигналы, фоновые задачи, управление сценариями / RUVDS.com corporate blog / Habr
Bash-скрипты: начало
Bash-скрипты, часть 2: циклы
Bash-скрипты, часть 3: параметры и ключи командной строки
Bash-скрипты, часть 4: ввод и вывод
Bash-скрипты, часть 5: сигналы, фоновые задачи, управление сценариями
Bash-скрипты, часть 6: функции и разработка библиотек
Bash-скрипты, часть 7: sed и обработка текстов
Bash-скрипты, часть 8: язык обработки данных awk
Bash-скрипты, часть 9: регулярные выражения
Bash-скрипты, часть 10: практические примеры
Bash-скрипты, часть 11: expect и автоматизация интерактивных утилит
В прошлый раз мы говорили о работе с потоками ввода, вывода и ошибок в bash-скриптах, о дескрипторах файлов и о перенаправлении потоков. Сейчас вы знаете уже достаточно много для того, чтобы писать что-то своё. На данном этапе освоения bash у вас вполне могут возникнуть вопросы о том, как управлять работающими скриптами, как автоматизировать их запуск.
До сих пор мы вводили имена скриптов в командную строку и нажимали Enter, что приводило к немедленному запуску программ, но это — не единственный способ вызова сценариев. Сегодня мы поговорим о том как скрипт может работать с сигналами Linux, о различных подходах к запуску скриптов и к управлению ими во время работы.
Сигналы Linux
В Linux существует более трёх десятков сигналов, которые генерирует система или приложения. Вот список наиболее часто используемых, которые наверняка пригодятся при разработке сценариев командной строки.
Код сигнала |
Название |
Описание |
1 |
SIGHUP |
Закрытие терминала |
2 |
SIGINT |
Сигнал остановки процесса пользователем с терминала (CTRL + C) |
3 |
SIGQUIT |
Сигнал остановки процесса пользователем с терминала (CTRL + \) с дампом памяти |
9 |
SIGKILL |
Безусловное завершение процесса |
15 |
SIGTERM |
Сигнал запроса завершения процесса |
17 |
SIGSTOP | Принудительная приостановка выполнения процесса, но не завершение его работы |
18 |
SIGTSTP |
Приостановка процесса с терминала (CTRL + Z), но не завершение работы |
19 |
SIGCONT |
Продолжение выполнения ранее остановленного процесса |
Если оболочка bash получает сигнал
SIGHUP
когда вы закрываете терминал, она завершает работу. Перед выходом она отправляет сигнал SIGHUP
всем запущенным в ней процессам, включая выполняющиеся скрипты.Сигнал SIGINT
приводит к временной остановке работы. Ядро Linux перестаёт выделять оболочке процессорное время. Когда это происходит, оболочка уведомляет процессы, отправляя им сигнал SIGINT
.
Bash-скрипты не контролируют эти сигналы, но они могут распознавать их и выполнять некие команды для подготовки скрипта к последствиям, вызываемым сигналами.
Отправка сигналов скриптам
Оболочка bash позволяет вам отправлять скриптам сигналы, пользуясь комбинациями клавиш на клавиатуре. Это оказывается очень кстати если нужно временно остановить выполняющийся скрипт или завершить его работу.
Завершение работы процесса
Комбинация клавиш
CTRL + C
генерирует сигнал SIGINT
и отправляет его всем процессам, выполняющимся в оболочке, что приводит к завершению их работы.Выполним в оболочке такую команду:
$ sleep 100
После этого завершим её работу комбинацией клавиш
CTRL + C
.Завершение работы процесса с клавиатуры
Временная остановка процесса
Комбинация клавиш
CTRL + Z
позволяет сгенерировать сигнал SIGTSTP
, который приостанавливает работу процесса, но не завершает его выполнение. Такой процесс остаётся в памяти, его работу можно возобновить. Выполним в оболочке команду:$ sleep 100
И временно остановим её комбинацией клавиш
CTRL + Z
Приостановка процесса
Число в квадратных скобках — это номер задания, который оболочка назначает процессу. Оболочка рассматривает процессы, выполняющиеся в ней, как задания с уникальными номерами. Первому процессу назначается номер 1, второму — 2, и так далее.
Если вы приостановите задание, привязанное к оболочке, и попытаетесь выйти из неё, bash выдаст предупреждение.
Просмотреть приостановленные задания можно такой командой:
ps –l
Список заданий
В колонке S
, выводящей состояние процесса, для приостановленных процессов выводится T
. Это указывает на то, что команда либо приостановлена, либо находится в состоянии трассировки.
Если нужно завершить работу приостановленного процесса, можно воспользоваться командой kill
. Подробности о ней можно почитать здесь.
Выглядит её вызов так:
kill processID
Перехват сигналов
Для того, чтобы включить в скрипте отслеживание сигналов Linux, используется команда
trap
. Если скрипт получает сигнал, указанный при вызове этой команды, он обрабатывает его самостоятельно, при этом оболочка такой сигнал обрабатывать не будет.Команда trap
позволяет скрипту реагировать на сигналы, в противном случае их обработка выполняется оболочкой без его участия.
Рассмотрим пример, в котором показано, как при вызове команды trap
задаётся код, который надо выполнить, и список сигналов, разделённых пробелами, которые мы хотим перехватить. В данном случае это всего один сигнал:
#!/bin/bash
trap "echo ' Trapped Ctrl-C'" SIGINT
echo This is a test script
count=1
while [ $count -le 10 ]
do
echo "Loop #$count"
sleep 1
count=$(( $count + 1 ))
done
Команда
trap
, использованная в этом примере, выводит текстовое сообщение всякий раз, когда она обнаруживает сигнал SIGINT
, который можно сгенерировать, нажав Ctrl + C
на клавиатуре.Перехват сигналов
Каждый раз, когда вы нажимаете клавиши CTRL + C
, скрипт выполняет команду echo
, указанную при вызове trace
вместо того, чтобы позволить оболочке завершит его работу.
Перехват сигнала выхода из скрипта
Перехватить сигнал выхода из скрипта можно, использовав при вызове команды
trap
имя сигнала EXIT
:#!/bin/bash
trap "echo Goodbye..." EXIT
count=1
while [ $count -le 5 ]
do
echo "Loop #$count"
sleep 1
count=$(( $count + 1 ))
done
Перехват сигнала выхода из скрипта
При выходе из скрипта, будь то нормальное завершение его работы или завершение, вызванное сигналом SIGINT
, сработает перехват и оболочка исполнит команду echo
.
Модификация перехваченных сигналов и отмена перехвата
Для модификации перехваченных скриптом сигналов можно выполнить команду
trap
с новыми параметрами:#!/bin/bash
trap "echo 'Ctrl-C is trapped.'" SIGINT
count=1
while [ $count -le 5 ]
do
echo "Loop #$count"
sleep 1
count=$(( $count + 1 ))
done
trap "echo ' I modified the trap!'" SIGINT
count=1
while [ $count -le 5 ]
do
echo "Second Loop #$count"
sleep 1
count=$(( $count + 1 ))
done
Модификация перехвата сигналов
После модификации сигналы будут обрабатываться по-новому.
Перехват сигналов можно и отменить, для этого достаточно выполнить команду trap
, передав ей двойное тире и имя сигнала:
#!/bin/bash
trap "echo 'Ctrl-C is trapped.'" SIGINT
count=1
while [ $count -le 5 ]
do
echo "Loop #$count"
sleep 1
count=$(( $count + 1 ))
done
trap -- SIGINT
echo "I just removed the trap"
count=1
while [ $count -le 5 ]
do
echo "Second Loop #$count"
sleep 1
count=$(( $count + 1 ))
done
Если скрипт получит сигнал до отмены перехвата, он обработает его так, как задано в действующей команде
trap
. Запустим скрипт:$ ./myscript
CTRL + C
на клавиатуре.Сигнал, перехваченный до отмены перехвата
Первое нажатие CTRL + C
пришлось на момент исполнения скрипта, когда перехват сигнала был в силе, поэтому скрипт исполнил назначенную сигналу команду echo
. После того, как исполнение дошло до команды отмены перехвата, команда CTRL + C
сработала обычным образом, завершив работу скрипта.
Выполнение сценариев командной строки в фоновом режиме
Иногда bash-скриптам требуется немало времени для выполнения некоей задачи. При этом вам может понадобиться возможность нормально работать в командной строке, не дожидаясь завершения скрипта. Реализовать это не так уж и сложно.
Если вы видели список процессов, выводимый командой ps
, вы могли заметить процессы, которые выполняются в фоне и не привязаны к терминалу.
Напишем такой скрипт:
#!/bin/bash
count=1
while [ $count -le 10 ]
do
sleep 1
count=$(( $count + 1 ))
done
Запустим его, указав после имени символ амперсанда (
&
):$ ./myscipt &
Это приведёт к тому, что он будет запущен как фоновый процесс.
Запуск скрипта в фоновом режиме
Скрипт будет запущен в фоновом процессе, в терминал выведется его идентификатор, а когда его выполнение завершится, вы увидите сообщение об этом.
Обратите внимание на то, что хотя скрипт выполняется в фоне, он продолжает использовать терминал для вывода сообщений в STDOUT
и STDERR
, то есть, выводимый им текст или сообщения об ошибках можно будет увидеть в терминале.
Список процессов
При таком подходе, если выйти из терминала, скрипт, выполняющийся в фоне, так же завершит работу.
Что если нужно, чтобы скрипт продолжал работать и после закрытия терминала?
Выполнение скриптов, не завершающих работу при закрытии терминала
Скрипты можно выполнять в фоновых процессах даже после выхода из терминальной сессии. Для этого можно воспользоваться командой
nohup
. Эта команда позволяет запустить программу, блокируя сигналы SIGHUP
, отправляемые процессу. В результате процесс будет исполняться даже при выходе из терминала, в котором он был запущен.Применим эту методику при запуске нашего скрипта:
nohup ./myscript &
Вот что будет выведено в терминал.
Команда nohup
Команда nohup
отвязывает процесс от терминала. Это означает, что процесс потеряет ссылки на STDOUT
и STDERR
. Для того, чтобы не потерять данные, выводимые скриптом, nohup
автоматически перенаправляет сообщения, поступающие в STDOUT
и в STDERR
, в файл nohup.out
.
Обратите внимание на то, что при запуске нескольких скриптов из одной и той же директории то, что они выводят, попадёт в один файл nohup.out
.
Просмотр заданий
Команда
jobs
позволяет просматривать текущие задания, которые выполняются в оболочке. Напишем такой скрипт: #!/bin/bash
count=1
while [ $count -le 10 ]
do
echo "Loop #$count"
sleep 10
count=$(( $count + 1 ))
done
Запустим его:
$ ./myscript
И временно остановим комбинацией клавиш
CTRL + Z
.Запуск и приостановка скрипта
Запустим тот же скрипт в фоновом режиме, при этом перенаправим вывод скрипта в файл так, чтобы он ничего не выводил на экране:
$ ./myscript > outfile &
Выполнив теперь команду
jobs
, мы увидим сведения как о приостановленном скрипте, так и о том, который работает в фоне.Получение сведений о скриптах
Ключ -l
при вызове команды jobs
указывает на то, что нам нужны сведения об ID
процессов.
Перезапуск приостановленных заданий
Для того, чтобы перезапустить скрипт в фоновом режиме, можно воспользоваться командой
bg
.Запустим скрипт:
$ ./myscript
Нажмём
CTRL + Z
$ bg
Команда bg
Теперь скрипт выполняется в фоновом режиме.
Если у вас имеется несколько приостановленных заданий, для перезапуска конкретного задания команде bg
можно передать его номер.
Для перезапуска задания в обычном режиме воспользуйтесь командой fg
:
$ fg 1
Планирование запуска скриптов
Linux предоставляет пару способов запуска bash-скриптов в заданное время. Это команда
at
и планировщик заданий cron
.Вызов команды at выглядит так:
at [-f filename] time
Эта команда распознаёт множество форматов указания времени.
- Стандартный, с указанием часов и минут, например — 10:15.
- С использованием индикаторов AM/PM, до или после полудня, например — 10:15PM.
- С использованием специальных имён, таких, как
now
,noon
,midnight
.
В дополнение к возможности указания времени запуска задания, команде
at
можно передать и дату, используя один из поддерживаемых ей форматов.- Стандартный формат указания даты, при котором дата записывается по шаблонам
MMDDYY
,MM/DD/YY
, илиDD.MM.YY
. - Текстовое представление даты, например,
Jul 4
илиDec 25
, при этом год можно указать, а можно обойтись и без него. - Запись вида
now + 25 minutes
. - Запись вида
10:15PM tomorrow
. - Запись вида
10:15 + 7 days
.
Не будем углубляться в эту тему, рассмотрим простой вариант использования команды:
$ at -f ./myscript now
Планирование заданий с использованием команды at
Ключ -M
при вызове at
используется для отправки того, что выведет скрипт, по электронной почте, если система соответствующим образом настроена. Если отправка электронного письма невозможна, этот ключ просто подавит вывод.
Для того чтобы посмотреть список заданий, ожидающих выполнения, можно воспользоваться командой atq
:
$ atq
Список заданий, ожидающих выполнения
Удаление заданий, ожидающих выполнения
Удалить задание, ожидающее выполнения, позволяет команда
atrm
. При её вызове указывают номер задания:$ atrm 18
Удаление задания
Запуск скриптов по расписанию
Планирование однократного запуска скриптов с использованием команды
at
способно облегчить жизнь во многих ситуациях. Но как быть, если нужно, чтобы скрипт выполнялся в одно и то же время ежедневно, или раз в неделю, или раз в месяц?В Linux имеется утилита crontab
, позволяющая планировать запуск скриптов, которые нужно выполнять регулярно.
Crontab
выполняется в фоне и, основываясь на данных в так называемых cron-таблицах, запускает задания по расписанию.
Для того, чтобы просмотреть существующую таблицу заданий cron
, воспользуйтесь такой командой:
$ crontab –l
При планировании запуска скрипта по расписанию
crontab
принимает данные о том, когда нужно выполнить задание, в таком формате:минута, час, день месяца, месяц, день недели.
Например, если надо, чтобы некий скрипт с именем
command
выполнялся ежедневно в 10:30, этому будет соответствовать такая запись в таблице заданий:30 10 * * * command
Здесь универсальный символ «
*
», использованный для полей, задающих день месяца, месяц и день недели, указывает на то, что cron
должен выполнять команду каждый день каждого месяца в 10:30.Если, например, надо, чтобы скрипт запускался в 4:30PM
каждый понедельник, понадобится создать в таблице заданий такую запись:
30 16 * * 1 command
Нумерация дней недели начинается с 0, 0 означает воскресенье, 6 — субботу. Вот ещё один пример. Здесь команда будет выполняться в 12 часов дня в первый день каждого месяца.
00 12 1 * * command
Нумерация месяцев начинается с 1.
Для того чтобы добавить запись в таблицу, нужно вызвать
crontab
с ключом -e
:crontab –e
Затем можно вводить команды формирования расписания:
30 10 * * * /home/likegeeks/Desktop/myscript
Благодаря этой команде скрипт будет вызываться ежедневно в 10:30. Если вы столкнётесь с ошибкой «Resource temporarily unavailable», выполните нижеприведённую команду с правами root-пользователя:
$ rm -f /var/run/crond.pid
Организовать периодический запуск скриптов с использованием
cron
можно ещё проще, воспользовавшись несколькими специальными директориями:/etc/cron.hourly
/etc/cron.daily
/etc/cron.weekly
/etc/cron.monthly
Если поместить файл скрипта в одну из них, это приведёт, соответственно, к его ежечасному, ежедневному, еженедельному или ежемесячному запуску.
Запуск скриптов при входе в систему и при запуске оболочки
Автоматизировать запуск скриптов можно, опираясь на различные события, такие, как вход пользователя в систему или запуск оболочки. Тут можно почитать о файлах, которые обрабатываются в подобных ситуациях. Например, это следующие файлы:
$HOME/.bash_profile
$HOME/.bash_login
$HOME/.profile
Для того, чтобы запускать скрипт при входе в систему, поместите его вызов в файл
.bash_profile
.А как насчёт запуска скриптов при открытии терминала? Организовать это поможет файл .bashrc
.
Итоги
Сегодня мы разобрали вопросы, касающиеся управления жизненным циклом сценариев, поговорили о том, как запускать скрипты в фоне, как планировать их выполнение по расписанию. В следующий раз читайте о функциях в bash-скриптах и о разработке библиотек.
Уважаемые читатели! А вы пользуетесь средствами планирования запуска сценариев командной строки по расписанию? Если да — расскажите пожалуйста о них.
практические примеры / RUVDS.com corporate blog / Habr
Bash-скрипты: начало
Bash-скрипты, часть 2: циклы
Bash-скрипты, часть 3: параметры и ключи командной строки
Bash-скрипты, часть 4: ввод и вывод
Bash-скрипты, часть 5: сигналы, фоновые задачи, управление сценариями
Bash-скрипты, часть 6: функции и разработка библиотек
Bash-скрипты, часть 7: sed и обработка текстов
Bash-скрипты, часть 8: язык обработки данных awk
Bash-скрипты, часть 9: регулярные выражения
Bash-скрипты, часть 10: практические примеры
Bash-скрипты, часть 11: expect и автоматизация интерактивных утилит
В предыдущих материалах мы обсуждали различные аспекты разработки 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.
Уважаемые читатели! Есть ли у вас на примете несложные (а может быть и сложные, но понятные) bash-скрипты, разбор которых будет полезен новичкам?
параметры и ключи командной строки / RUVDS.com corporate blog / Habr
Bash-скрипты: начало
Bash-скрипты, часть 2: циклы
Bash-скрипты, часть 3: параметры и ключи командной строки
Bash-скрипты, часть 4: ввод и вывод
Bash-скрипты, часть 5: сигналы, фоновые задачи, управление сценариями
Bash-скрипты, часть 6: функции и разработка библиотек
Bash-скрипты, часть 7: sed и обработка текстов
Bash-скрипты, часть 8: язык обработки данных awk
Bash-скрипты, часть 9: регулярные выражения
Bash-скрипты, часть 10: практические примеры
Bash-скрипты, часть 11: expect и автоматизация интерактивных утилит
Освоив предыдущие части этой серии материалов, вы узнали о том, что такое bash-скрипты, как их писать, как управлять потоком выполнения программы, как работать с файлами. Сегодня мы поговорим о том, как добавить скриптам интерактивности, оснастив их возможностями по получению данных от пользователя и по обработке этих данных.
Наиболее распространённый способ передачи данных сценариям заключается в использовании параметров командной строки. Вызвав сценарий с параметрами, мы передаём ему некую информацию, с которой он может работать. Выглядит это так:
$ ./myscript 10 20
В данном примере сценарию передано два параметра — «10» и «20». Всё это хорошо, но как прочесть данные в скрипте?
Чтение параметров командной строки
Оболочка bash назначает специальным переменным, называемым позиционными параметрами, введённые при вызове скрипта параметры командной строки:
$0 —
имя скрипта.$1 —
первый параметр.$2 —
второй параметр — и так далее, вплоть до переменной$9
, в которую попадает девятый параметр.
Вот как можно использовать параметры командной строки в скрипте с помощью этих переменных:
#!/bin/bash
echo $0
echo $1
echo $2
echo $3
Запустим сценарий с параметрами:
./myscript 5 10 15
Вот что он выведет в консоль.
Вывод параметров, с которыми запущен скрипт
Обратите внимание на то, что параметры командной строки разделяются пробелами.
Взглянем на ещё один пример использования параметров. Тут мы найдём сумму чисел, переданных сценарию:
#!/bin/bash
total=$[ $1 + $2 ]
echo The first parameter is $1.
echo The second parameter is $2.
echo The sum is $total.
Запустим скрипт и проверим результат вычислений.
Сценарий, который находит сумму переданных ему чисел
Параметры командной строки не обязательно должны быть числами. Сценариям можно передавать и строки. Например, вот скрипт, работающий со строкой:
#!/bin/bash
echo Hello $1, how do you do
Запустим его:
./myscript Adam
Он выведет то, что мы от него ожидаем.
Сценарий, работающий со строковым параметром
Что если параметр содержит пробелы, а нам надо обрабатывать его как самостоятельный фрагмент данных? Полагаем, если вы освоили предыдущие части этого руководства, ответ вы уже знаете. Заключается он в использовании кавычек.
Если скрипту надо больше девяти параметров, при обращении к ним номер в имени переменной надо заключать в фигурные скобки, например так:
${10}
Проверка параметров
Если скрипт вызван без параметров, но для нормальной работы кода предполагается их наличие, возникнет ошибка. Поэтому рекомендуется всегда проверять наличие параметров, переданных сценарию при вызове. Например, это можно организовать так:
#!/bin/bash
if [ -n "$1" ]
then
echo Hello $1.
else
echo "No parameters found. "
fi
Вызовем скрипт сначала с параметром, а потом без параметров.
Вызов скрипта, проверяющего наличие параметров командной строки
Подсчёт параметров
В скрипте можно подсчитать количество переданных ему параметров. Оболочка bash предоставляет для этого специальную переменную. А именно, переменная
$#
содержит количество параметров, переданных сценарию при вызове.Опробуем её:
#!/bin/bash
echo There were $# parameters passed.
Вызовем сценарий.
./myscript 1 2 3 4 5
В результате скрипт сообщит о том, что ему передано 5 параметров.
Подсчёт количества параметров в скрипте
Эта переменная даёт необычный способ получения последнего из переданных скрипту параметров, не требующий знания их количества. Вот как это выглядит:
#!/bin/bash
echo The last parameter was ${!#}
Вызовем скрипт и посмотрим, что он выведет.
Обращение к последнему параметру
Захват всех параметров командной строки
В некоторых случаях нужно захватить все параметры, переданные скрипту. Для этого можно воспользоваться переменными
$*
и $@
. Обе они содержат все параметры командной строки, что делает возможным доступ к тому, что передано сценарию, без использования позиционных параметров.Переменная $*
содержит все параметры, введённые в командной строке, в виде единого «слова».
В переменной $@
параметры разбиты на отдельные «слова». Эти параметры можно перебирать в циклах.
Рассмотрим разницу между этими переменными на примерах. Сначала взглянем на их содержимое:
#!/bin/bash
echo "Using the \$* method: $*"
echo "-----------"
echo "Using the \$@ method: $@"
Вот вывод скрипта.
Переменные $* и $@
Как видно, при выводе обеих переменных получается одно и то же. Теперь попробуем пройтись по содержимому этих переменных в циклах для того, чтобы увидеть разницу между ними:
#!/bin/bash
count=1
for param in "$*"
do
echo "\$* Parameter #$count = $param"
count=$(( $count + 1 ))
done
count=1
for param in "$@"
do
echo "\$@ Parameter #$count = $param"
count=$(( $count + 1 ))
done
Взгляните на то, что скрипт вывел в консоль. Разница между переменными вполне очевидна.
Разбор переменных $* и $@ в цикле
Переменная $*
содержит все переданные скрипту параметры как единый фрагмент данных, в то время как в переменной $@
они представлены самостоятельными значениями. Какой именно переменной воспользоваться — зависит от того, что именно нужно в конкретном сценарии.
Команда shift
Использовать команду
shift
в bash-скриптах следует с осторожностью, так как она, в прямом смысле слова, сдвигает значения позиционных параметров.Когда вы используете эту команду, она, по умолчанию, сдвигает значения позиционных параметров влево. Например, значение переменной $3
становится значением переменной $2
, значение $2
переходит в $1
, а то, что было до этого в $1,
теряется. Обратите внимание на то, что при этом значение переменной $0
, содержащей имя скрипта, не меняется.
Воспользовавшись командой shift
, рассмотрим ещё один способ перебора переданных скрипту параметров:
#!/bin/bash
count=1
while [ -n "$1" ]
do
echo "Parameter #$count = $1"
count=$(( $count + 1 ))
shift
done
Скрипт задействует цикл
while
, проверяя длину значения первого параметра. Когда длина станет равна нулю, происходит выход из цикла. После проверки первого параметра и вывода его на экран, вызывается команда shift
, которая сдвигает значения параметров на одну позицию.Использование команды shift для перебора параметров
Используя команду shift
, помните о том, что при каждом её вызове значение переменной $1
безвозвратно теряется.
Ключи командной строки
Ключи командной строки обычно выглядят как буквы, перед которыми ставится тире. Они служат для управления сценариями. Рассмотрим такой пример:
#!/bin/bash
echo
while [ -n "$1" ]
do
case "$1" in
-a) echo "Found the -a option" ;;
-b) echo "Found the -b option" ;;
-c) echo "Found the -c option" ;;
*) echo "$1 is not an option" ;;
esac
shift
done
Запустим скрипт:
$ ./myscript –a –b –c –d
И проанализируем то, что он выведет в терминал.
Обработка ключей в скрипте
В этом коде использована конструкция case
, которая сверяет переданный ей ключ со списком обрабатываемых скриптом ключей. Если переданное значение нашлось в этом списке, выполняется соответствующая ветвь кода. Если при вызове скрипта будет использован любой ключ, обработка которого не предусмотрена, будет исполнена ветвь «*».
Как различать ключи и параметры
Часто при написании bash-скриптов возникает ситуация, когда надо использовать и параметры командной строки, и ключи. Стандартный способ это сделать заключается в применении специальной последовательности символов, которая сообщает скрипту о том, когда заканчиваются ключи и начинаются обычные параметры.
Эта последовательность — двойное тире (—). Оболочка использует её для указания позиции, на которой заканчивается список ключей. После того, как скрипт обнаружит признак окончания ключей, то, что осталось, можно, не опасаясь ошибок, обрабатывать как параметры, а не как ключи. Рассмотрим пример:
#!/bin/bash
while [ -n "$1" ]
do
case "$1" in
-a) echo "Found the -a option" ;;
-b) echo "Found the -b option";;
-c) echo "Found the -c option" ;;
--) shift
break ;;
*) echo "$1 is not an option";;
esac
shift
done
count=1
for param in $@
do
echo "Parameter #$count: $param"
count=$(( $count + 1 ))
done
Этот сценарий использует команду
break
для прерывания цикла while
при обнаружении в строке двойного тире.Вот что получится после его вызова.
Обработка ключей и параметров командной строки
Как видно, когда скрипт, разбирая переданные ему данные, находит двойное тире, он завершает обработку ключей и считает всё, что ещё не обработано, параметрами.
Обработка ключей со значениями
По мере усложнения ваших скриптов, вы столкнётесь с ситуациями, когда обычных ключей уже недостаточно, а значит, нужно будет использовать ключи с некими значениями. Например, вызов сценария в котором используется подобная возможность, выглядит так:
./myscript -a test1 -b -c test2
Скрипт должен уметь определять, когда вместе с ключами командной строки используются дополнительные параметры:
#!/bin/bash
while [ -n "$1" ]
do
case "$1" in
-a) echo "Found the -a option";;
-b) param="$2"
echo "Found the -b option, with parameter value $param"
shift ;;
-c) echo "Found the -c option";;
--) shift
break ;;
*) echo "$1 is not an option";;
esac
shift
done
count=1
for param in "$@"
do
echo "Parameter #$count: $param"
count=$(( $count + 1 ))
done
Вызовем этот скрипт в таком виде:
./myscript -a -b test1 -d
Посмотрим на результаты его работы.
Обработка параметров ключей
В данном примере в конструкции case
обрабатываются три ключа. Ключ -b
требует наличия дополнительного параметра. Так как обрабатываемый ключ находится в переменной $1
, соответствующий ему параметр будет находиться в $2
(тут используется команда shift
, поэтому, по мере обработки, всё, что передано сценарию, сдвигается влево). Когда с этим мы разобрались, осталось лишь извлечь значение переменной $2
и у нас будет параметр нужного ключа. Конечно, тут понадобится ещё одна команда shift
для того, чтобы следующий ключ попал в $1
.
Использование стандартных ключей
При написании bash-скриптов вы можете выбирать любые буквы для ключей командной строки и произвольно задавать реакцию скрипта на эти ключи. Однако, в мире Linux значения некоторых ключей стали чем-то вроде стандарта, которого полезно придерживаться. Вот список этих ключей:
-a
Вывести все объекты.-c
Произвести подсчёт.-d
Указать директорию.-e
Развернуть объект.-f
Указать файл, из которого нужно прочитать данные.-h
Вывести справку по команде.-i
Игнорировать регистр символов.-l
Выполнить полноформатный вывод данных.-n
Использовать неинтерактивный (пакетный) режим.-o
Позволяет указать файл, в который нужно перенаправить вывод.-q
Выполнить скрипт в quiet-режиме.-r
Обрабатывать папки и файлы рекурсивно.-s
Выполнить скрипт в silent-режиме.-v
Выполнить многословный вывод.-x
Исключить объект.-y
Ответить «yes» на все вопросы.
Если вы работаете в Linux, вам, скорее всего, знакомы многие из этих ключей. Использовав их в общепринятом значении в своих скриптах, вы поможете пользователям взаимодействовать с ними, не беспокоясь о чтении документации.
Получение данных от пользователя
Ключи и параметры командной строки — это отличный способ получить данные от того, кто пользуется скриптом, однако в некоторых случаях нужно больше интерактивности.
Иногда сценарии нуждаются в данных, которые пользователь должен ввести во время выполнения программы. Именно для этой цели в оболочке bash имеется команда read
.
Эта команда позволяет принимать введённые данные либо со стандартного ввода (с клавиатуры), либо используя другие дескрипторы файлов. После получения данных, эта команда помещает их в переменную:
#!/bin/bash
echo -n "Enter your name: "
read name
echo "Hello $name, welcome to my program."
Обратите внимание на то, что команда
echo
, которая выводит приглашение, вызывается с ключом -n
. Это приводит к тому, что в конце приглашения не выводится знак перевода строки, что позволяет пользователю скрипта вводить данные там же, где расположено приглашение, а не на следующей строке.Обработка пользовательского ввода
При вызове read
можно указывать и несколько переменных:
#!/bin/bash
read -p "Enter your name: " first last
echo "Your data for $last, $first…"
Вот что выведет скрипт после запуска.
Несколько переменных в команде read
Если, вызвав read
, не указывать переменную, данные, введённые пользователем, будут помещены в специальную переменную среды REPLY
:
#!/bin/bash
read -p "Enter your name: "
echo Hello $REPLY, welcome to my program.
Использование переменной среды REPLY
Если скрипт должен продолжать выполнение независимо от того, введёт пользователь какие-то данные или нет, вызывая команду read
можно воспользоваться ключом -t
. А именно, параметр ключа задаёт время ожидания ввода в секундах:
#!/bin/bash
if read -t 5 -p "Enter your name: " name
then
echo "Hello $name, welcome to my script"
else
echo "Sorry, too slow! "
fi
Если данные не будут введены в течение 5 секунд, скрипт выполнит ветвь условного оператора
else
, выведя извинения.Ограничение времени на ввод данных
Ввод паролей
Иногда то, что вводит пользователь в ответ на вопрос скрипта, лучше на экране не показывать. Например, так обычно делают, запрашивая пароли. Ключ
-s
команды read
предотвращает отображение на экране данных, вводимых с клавиатуры. На самом деле, данные выводятся, но команда read
делает цвет текста таким же, как цвет фона.#!/bin/bash
read -s -p "Enter your password: " pass
echo "Is your password really $pass? "
Вот как отработает этот скрипт.
Ввод конфиденциальных данных
Чтение данных из файла
Команда
read
может, при каждом вызове, читать одну строку текста из файла. Когда в файле больше не останется непрочитанных строк, она просто остановится. Если нужно получить в скрипте всё содержимое файла, можно, с помощью конвейера, передать результаты вызова команды cat
для файла, конструкции while
, которая содержит команду read
(конечно, использование команды cat
выглядит примитивно, но наша цель — показать всё максимально просто, ориентируясь на новичков; опытные пользователи, уверены, это поймут).Напишем скрипт, в котором используется только что описанный подход к чтению файлов.
#!/bin/bash
count=1
cat myfile | while read line
do
echo "Line $count: $line"
count=$(( $count + 1 ))
done
echo "Finished"
Посмотрим на него в деле.
Чтение данных из файла
Тут мы передали в цикл while
содержимое файла и перебрали все строки этого файла, выводя номер и содержимое каждой из них.
Итоги
Сегодня мы разобрали работу с ключами и параметрами командной строки. Без этих средств диапазон использования скриптов оказывается чрезвычайно узким. Даже если скрипт написан, что называется, «для себя». Тут же мы рассмотрели подходы к получению данных от пользователя во время выполнения программы — это делает сценарии интерактивными.
В следующий раз поговорим об операциях ввода и вывода.
Уважаемые читатели! Спасибо вам за то, что делитесь опытом в комментариях к предыдущим частям этого цикла материалов. Если вам есть что сказать об обработке всего того, что можно передать в скрипт при запуске или во время его работы, уверены, многим будет интересно об этом почитать.
Userscripts. Углубляемся / Habr
Как упоминалось в предыдущей статье, юзерскрипты поддерживаются всеми современными браузерами. И даже кое-как поддерживаются в IE7 и выше.В этой статье мы поговорим о браузерах:
- Ограничения
- Проблемы
- Расширения для запуска юзерскриптов
- Установка юзерскриптов
Пару слов о движках
Качество поддержки юзерскриптов находится на разном уровне в разных браузерах. Лучше всего поддержка юзерскриптов выполнена в браузерах Firefox и Chrome.
Эти браузеры предоставляют более менее дружелюбные интерфейсы для управления юзерскриптами.
Самые жесткие ограничения на юзерскрипты накладывает Chrome. Но почти все эти ограничения обходятся упаковыванием скрипта в простое расширение. Подробности этого процесса мы обсудим в следующей статье.
Теперь поговорим подробнее о поддержке юзерскриптов в отдельных браузерах.
Поддержка в Firefox
Mozilla Firefox поддерживает юзерскрипты после установки расширения GreaseMonkey (в русском сленге — обезъяна) или Scriptish.
После установки расширений фаерфокс получает поистине мощную поддержку юзерскриптов.
Рассматриваемая далее информация применима в первую очередь к GreaseMonkey (это расширение было первым).
Установка: юзерскрипты устанавливаются простым перетаскиванием файла скрипта в браузер.
Расширения: GreaseMonkey, Scriptish.
Управление: юзерскрипты можно отключить и удалить в меню, добавляемом расширениями.
Особенности:
- Присутстует мощная библиотека GM API.
- Подменяется «родной» глобальный объект window.
- Объекты «родного» окна, к примеру window.page_defined_var, доступны через «небезопасную» ссылку unsafeWindow.
- Доступны кроссдоменные запросы через интерфейс XmlHttpRequest.
- Доступен аналог globalStorage.
- Доступна возможность подключения сторонних библиотек (к примеру, jQuery).
- Из-за безопасности плагина GreaseMonkey некоторые функции требуют специфических хаков.
К примеру, запуск GM_setValue(…) в обработчике ajax-запроса может вызвать ошибку доступа к методам GM API. Для обработки такой ситуации используется конструкция вида setTimeout(function(){GM_setValue(…)},0). - Отсутствует возможность дебага юзерскриптов. Даже Firebug тут не поможет.
GreaseMonkey добавляет так называемый GM API — набор javascript функций, добавляющих функционал юзерскриптам.
Из самых востребованных функций, которые предоставляет GM API, стоит упомянуть:
- Объект «родного окна» страницы unsafeWindow (позволяет подменять функции на странице, использовать уже имеющиеся на странице библиотеки)
- Кроссдоменный HttpXmlRequest: GM_xmlhttpRequest
- Аналог globalStorage (localStorage без привязки к домену): GM_setValue,GM_getValue и GM_deleteValue
Подробнее о GM API и функциональности GreaseMoneky можно узнать на http://wiki.greasespot.net.
Исторически, все юзерскрипты писались под браузер Firefox именно из-за наличия удобного плагина.
Это обусловливает тот факт, что все браузеры, которые поддерживают юзерскрипты, дополнительно следуют основным правилам спецификации GreaseMonkey по разбору метаданных.
Это означает, что все скрипты, которые были написаны под GreaseMonkey, будут устанавливаться и запускаться в браузерах, поддерживающих юзерскрипты (с минимумом модификаций).
К сожалению, ни один браузер, кроме Firefox, не предоставляет GM API. Этот печальный факт заставляет использовать эмуляции GM API через расширения или дополнительные юзерскрипты.
В случае разработки юзерскрипта «с нуля», я считаю предпочтительным отказаться от эмуляции GM API и использовать «велосипеды» собственного производства. Это позволяет уменьшить число зависимостей юзерскрипта, что, в свою очередь, позволяет вести разработку в рамках концепции одного файла: модифицировать придётся всего один файл; пользователю нужен всего один файл для запуска юзерскрипта.
Концепция одного файла позволяет существенно уменьшить сложность поддержки и кроссбраузерной разработки юзерскриптов!
Поддержка в Chrome
Google Chrome поддерживает юзерскрипты нативно, т.е. не требует установки плагинов/расширений. Можно (иногда нужно) упаковать юзерскрипт в расширение.
Установка: юзерскрипты устанавливаются простым перетаскиванием файла скрипта в браузер.
Расширения: не нужны. Имеется расширение Tampermonkey, которое упрощает работу со скриптами.
Управление: юзерскрипты, как и расширения, можно отключить и удалить (Настройки -> Инструменты -> Расширения).
Особенности:
- Не доступен document.frames[i].parent (разрешено в расширении).
- Не доступны объекты родного окна, к примеру window.page_defined_var (подменить функции страницы будет нельзя, JSONP в юзерскрипте тоже отпадает)
- Не доступны кроссдоменные запросы (разрешены в расширении)
- unsafeWindow доступен, но не несёт функциональности GM API.
- Удобный нативный debug юзерскриптов и расширений.
Расширение представляет собой архив, упаковываемый самим браузером (Настройки -> Инструменты -> Расширения -> Упаковать расширение).
Помимо файла юзерскрипта расширение должно содержать:
- manifest.json — файл описания расширения. Аналог метаданных юзерскрипа.
- background.html — файл «фоновой страницы» расширения. Даёт доступ к API расширений через вызов методов chrome.extension.*
Упаковывание юзерскрипта в расширение позволяет обойти многие ограничения, наложенные Google Chrome на юзерскрипты.
Важно: фактически, расширение и юзерскрипт — разные понятия. И если подходить к вопросу строго, стоит говорить о разработке простых расширений под Chrome.
В случае, когда юзерскрипт требует нестандартного, «тяжелого» функционала, он требует упаковки в расширение.
Для упаковывания юзерскрипта в расширение нужно проделать дополнительные действия один раз. Вся последующая разработка будет вестись в рамках концепции одного файла.
Поддержка в Opera
Opera поддерживает юзерскрипты нативно, но не предоставляет сколь-нибудь дружелюбного пользовательского интерфейса для управления скриптами. Такой интерфейс доступен в расширении UJS Manager.
Расширения: UJS Manager, программа UserJS Manager.
Установка: юзерскрипты устанавливаются в настроенную пользователем папку пользовательских скриптов. Её расположение можно задать в настройках браузера: Настройки -> Общие настройки -> Расширенные -> Содержимое -> Настроить JavaScript. Папка с юзерскриптами не должна содержать пробелов.
Управление: юзерскрипты можно отключить, удалив или переместив файл скрипта из папки пользовательских скриптов.
Особенности:
- Юзерскрипты запускаются «как есть», не оборачиваясь в замыкание, тем самым засоряя глобальную область видимости window.
- Доступны объекты родного окна, к примеру window.page_defined_var.
- Доступные специфические события браузера Opera, к примеру BeforeScript.
- Не доступны кроссдоменные запросы (Обходится использованием специальных событий)
- unsafeWindow недоступен.
- Скрипты запускаются в алфавитном порядке.
Поддержка в IE
IE7, IE8, IE9 поддерживают юзерскрипты при использовании плагина Trixie.
К тому же, имеется более продвинутый плагин IE7Pro. В IE7Pro помимо поддержки юзерскриптов имеется множество других
Важно: Если не отключать дополнительные «приблуды» в IE7Pro, то плагин может изрядно тормозить браузер, особенно на тяжёлых страницах.
Расширения:Trixie, IE7Pro.
Установка: юзерскрипты устанавливаются в папку пользовательских скриптов Trixie (C:/Program Files/Bhelpuri/Trixie/Scripts) или IE7Pro (C:/Program Files/IEPro/userscripts).
Управление: у каждого плагина есть пользовательский интерфейс для управления юзерскриптами.
Особенности:
- Юзерскрипты запускаются «как есть», не оборачиваясь в замыкание, тем самым засоряя глобальную область видимости window.
- Доступны объекты родного окна, к примеру window.page_defined_var.
- Не доступны кроссдоменные запросы (Обойти можно способами, аналогичными тем, что используются при разработке на javascript: JSONP, easyXDM xdr и т.д.)
- unsafeWindow недоступен.
- И Trixie, и IEPro имеют модель загрузки скриптов, отличную от модели GreaseMonkey. Скрипты не перезапускаются при обновлении страницы через Ctrl+R или Ctrl+F5. К тому же, скрипты подгружаются по window.onLoad.
- Для того, чтобы Trixie увидел скрипт, скрипт должен иметь метаданные и обязательно иметь директиву @namespace (см. предыдущую статью).
- Для того, чтобы IE7Pro увидел скрипт, скрипт должен иметь расширение .ieuser.js.
- Оба плагина имеют проблемы с запуском в IE9 под Windows 7×64.
Сообщения о незапускаемом IE7Pro я встречал чаще.
Как видите, с запуском скриптов у IE дела обстоят паршиво. Остаётся радоваться, что такая возможность вообще имеется.
Важно: Оба плагина могут существовать в системе одновременно, не мешая друг другу.
Важно: Учитывая вышесказанное, я всегда предлагаю своим пользователям использовать Trixie.
Поддержка в Safari
К сожалению, мне не довелось поработать с данным браузером. Буду рад любым разъяснениям в комментариях!
Поговаривают, что для Safari нужны SIMBL и плагин GreaseKit.
Поддержка в Mobile Safari и прочих браузерах
В виду отсутствия поддержки юзерскриптов в менее популярных браузерах и мобильных браузерах, юзерскрипты придётся предоставлять в виде букмарклета.
Соотстветственно, метаданные в таком случае не нужны, а букмарклет придётся запускать руками после каждого рефреша.
На последок
Если придерживаться концепции одного файла, то процесс созидания идёт по такому пути:
- Берём шаблон.
- Добавляем
водукод и метаданные. - Создаём папку и файлы для расширения Chrome.
- Пакуем расширение для Chrome, переименовываем файл для IE7Pro.
- Раздаём юзерскрипт/расширение пользователям.
- …
- Исправляем
рукибаги. - GoTo 4
Список статей:
- Учимся писать userscript’ы
- » Userscripts. Углубляемся.
- Userscripts. Упаковываем юзерскрипт для Chrome
- Usersctripts. Кроссдоменные запросы
CallScripts — бесплатный конструктор скриптов звонков
Полезная информация.
В каких случаях используются холодные звонки, и нужен скрипт холодных звонков.
Этот инструмент активных продаж является неотъемлемым при продажах в сфере В2В. В последнее время холодные звонки стали чаще использоваться и в работе с обычными людьми.
Холодные звонки чаще используются в следующих направлениях бизнеса:
- экспедиторские компании – реклама работает редко, а клиенты разбросаны по всей стране и за рубежом, нет возможности личной встречи;
- рекламные агентства, журналы, печатные издательства – используют звонки для поиска новых рекламодателей;
- производственные компании, продающие товары для бизнеса – для поиска новых рынков сбыта, расширения базы клиентов;
- оптовые компании, продающие товары для организаций;
- агентства недвижимости — с целью продажи коммерческой недвижимости.
Схема разговора
Отметим, что универсальных скриптов быть не может – все целиком упирается в потребности компании, а самое главное – в то, что представляет собой целевая аудитория. Если вы хорошо представляете себе свою ЦА и знаете, кем является ЛПР (лицо, принимающее решение), то у вас не должно возникнуть проблем с составлением и последующей оптимизацией скрипта.
Базовая основа любого скрипта выглядит следующим образом:
1. Приветствие
«Здравствуйте», «Добрый день» и т.п.
2. Представление
«Меня зовут Николай, компания X».
3. Причина звонка
«Вы обращались к нам год назад», «Пытались сделать заказ на сайте», «Нам рекомендовал связаться с Вами Иван Иванович Иванов» и т.д.
4. Описание того, как будет проходить ваша беседа
«Предлагаю поступить так…» – далее следует объяснить, что именно получит клиент в процессе разговора. Также важно дать понять собеседнику, что никто не будет настаивать на продаже и ваше дело – просто поинтересоваться, не нужна ли ему определенная услуга или товар.
5. Вопросы
Задайте клиенту те вопросы, которые помогут вам лучше понять, что именно ему нужно на самом деле. Подобные вопросы могут касаться размера бюджета, сроков выполнения какого-либо проекта и так далее.
6. Развилки
Один из ключевых элементов любого скрипта. Вам необходимо просчитать все варианты ответов на вопросы и возражения клиентов, увеличивая шансы на успешный результат беседы. Сделать это можно имея соответствующий опыт общения со своей ЦА. Оптимизированный таким образом скрипт может значительно повысить конверсию.
Плюсы и минусы холодных звонков
Основными преимуществами холодных звонков являются:
- экономия времени и денег, в связи с отсутствием необходимости осуществлять разъезды при первом знакомстве с клиентом;
- более быстрое общение по телефону в сравнении с перепиской;
- возможность понять реакцию клиента по телефону на полученную информацию;
- возможность в разговоре задать уточняющие вопросы, устранить недопонимание;
- возможность при телефонном разговоре разложить перед собой шпаргалки и нужные документы и заглядывать в них при необходимости.
Холодные звонки имеют и ограничения, которые необходимо преодолевать:
- собеседник воспринимает звонок как помеху, отвлекаясь на него от своих дел;
- клиенту легче отказать или придумать отговорки по телефону;
- оппонент в любой момент может закончить разговор и повесить трубку;
- невозможно отследить реакцию человека, так как не видно жестов, мимики, можно сделать выводы о реакции только по интонации;
- нет возможности подкрепить слова графиками, изображениями;
- при телефонном звонке большая вероятность неверных толкований.