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

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


Скачать 3.58 Mb.
НазваниеBash скрипты
Анкорвцуйф ауцй
Дата15.08.2022
Размер3.58 Mb.
Формат файлаpdf
Имя файлаbash.pdf
ТипРуководство
#646431
страница3 из 6
1   2   3   4   5   6
Перенаправление ввода в скриптах Для перенаправления ввода можно воспользоваться той же методикой, которую мы применяли для перенаправления вывода. Например, команда exec позволяет сделать источником данных для STDIN какой-нибудь файл

48 exec 0< myfile Эта команда указывает оболочке на то, что источником вводимых данных должен стать файла необычный. Посмотрим на перенаправление ввода в действии
#!/bin/bash exec 0< testfile count=1 while read line do echo "Line #$count: $line" count=$(( $count + 1 )) done Вот что появится на экране после запуска скрипта.
Перенаправление ввода Водном из предыдущих материалов вы узнали о том, как использовать команду read для чтения данных, вводимых пользователем с клавиатуры. Если перенаправить ввод, сделав источником данных файл, то команда read, при попытке прочитать данные из STDIN, будет читать их из файла, а нес клавиатуры. Некоторые администраторы Linux используют этот подход для чтения и последующей обработки лог- файлов. Создание собственного перенаправления вывода Перенаправляя вводи вывод в сценариях, вы не ограничены тремя стандартными дескрипторами файлов. Как уже говорилось, можно иметь до девяти открытых дескрипторов. Остальные шесть, с номерами от 3 до 8, можно использовать для перенаправления ввода или вывода. Любой из них можно назначить файлу и использовать в коде скрипта. Назначить дескриптор для вывода данных можно, используя команду exec:
#!/bin/bash exec 3>myfile echo "This should display on the screen" echo "and this should be stored in the file" >&3 echo "And this should be back on the screen"

49 После запуска скрипта часть вывода попадёт на экран, часть — в файл с дескриптором 3.
Перенаправление вывода, используя собственный дескриптор Создание дескрипторов файлов для ввода данных Перенаправить ввод в скрипте можно точно также, как и вывод. Сохраните STDIN в другом дескрипторе, прежде чем перенаправлять ввод данных. После окончания чтения файла можно восстановить STDIN и пользоваться им как обычно
#!/bin/bash exec 6<&0 exec 0< myfile count=1 while read line do echo "Line #$count: $line" count=$(( $count + 1 )) done exec 0<&6 read -p "Are you done now? " answer case $answer in y) echo "Goodbye";; n) echo "Sorry, this is the end.";; esac Испытаем сценарий.

50
Перенаправление ввода В этом примере дескриптор файла 6 использовался для хранения ссылки на STDIN. Затем было сделано перенаправление ввода, источником данных для STDIN стал файл. После этого входные данные для команды read поступали из перенаправленного STDIN, то есть из файла. После чтения файла мы возвращаем STDIN в исходное состояние, перенаправляя его в дескриптор 6. Теперь, для того, чтобы проверить, что всё работает правильно, скрипт задаёт пользователю вопрос, ожидает ввода с клавиатуры и обрабатывает то, что введено. Закрытие дескрипторов файлов Оболочка автоматически закрывает дескрипторы файлов после завершения работы скрипта. Однако, в некоторых случаях нужно закрывать дескрипторы вручную, до того, как скрипт закончит работу. Для того, чтобы закрыть дескриптор, его нужно перенаправить в &-. Выглядит это так
#!/bin/bash exec 3> myfile echo "This is a test line of data" >&3 exec 3>&- echo "This won't work" >&3 После исполнения скрипта мы получим сообщение об ошибке. Попытка обращения к закрытому дескриптору файла

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


51 Для того, чтобы получить список всех открытых в Linux дескрипторов, можно воспользоваться командой lsof. Во многих дистрибутивах, вроде Fedora, утилита lsof находится в /usr/sbin. Эта команда весьма полезна, так как она выводит сведения о каждом дескрипторе, открытом в системе. Сюда входит и то, что открыли процессы, выполняемые в фоне, и то, что открыто пользователями, вошедшими в систему. У этой команды есть множество ключей, рассмотрим самые важные.
● -p Позволяет указать ID процесса.
● -d Позволяет указать номер дескриптора, о котором надо получить сведения. Для того, чтобы узнать PID текущего процесса, можно использовать специальную переменную окружения $$, в которую оболочка записывает текущий PID. Ключ -a используется для выполнения операции логического И над результатами, возвращёнными благодаря использованию двух других ключей lsof -a -p $$ -d 0,1,2 Вывод сведений об открытых дескрипторах Тип файлов, связанных си, символьный режим. Так как все они указывают на терминал, имя файла соответствует имени устройства, назначенного терминалу. Все три стандартных файла доступны и для чтения, и для записи. Посмотрим на вызов команды lsof из скрипта, в котором открыты, в дополнение к стандартным, другие дескрипторы
#!/bin/bash exec 3> myfile1 exec 6> myfile2 exec 7< myfile3 lsof -a -p $$ -d 0,1,2,3,6,7 Вот что получится, если этот скрипт запустить. Просмотр дескрипторов файлов, открытых скриптом


52 Скрипт открыл два дескриптора для вывода (3 и 6) и один — для ввода (7). Тут же показаны и пути к файлам, использованных для настройки дескрипторов. Подавление вывода Иногда надо сделать так, чтобы команды в скрипте, который, например, может исполняться как фоновый процесс, ничего не выводили на экран. Для этого можно перенаправить вывод в /dev/null. Это
— что-то вроде «чёрной дыры. Вот, например, как подавить вывод сообщений об ошибках ls -al badfile anotherfile 2> /dev/null Тот же подход используется, если, например, надо очистить файл, не удаляя его cat /dev/null > myfile Итоги Сегодня вы узнали о том, как в сценариях командной строки работают вводи вывод. Теперь вы умеете обращаться с дескрипторами файлов, создавать, просматривать и закрывать их, знаете о перенаправлении потоков ввода, вывода и ошибок. Всё это очень важно в деле разработки bash- скриптов. В следующий раз поговорим о сигналах Linux, о том, как обрабатывать их в сценариях, о запуске заданий по расписанию и о фоновых задачах.

53 скрипты, часть 5: сигналы, фоновые задачи, управление сценариями В прошлый раз мы говорили о работе с потоками ввода, вывода и ошибок в скриптах, о дескрипторах файлов и о перенаправлении потоков. Сейчас вызнаете уже достаточно много для того, чтобы писать что-то своё. На данном этапе освоения 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.

54
Bash- скрипты не контролируют эти сигналы, но они могут распознавать их и выполнять некие команды для подготовки скрипта к последствиям, вызываемым сигналами. Отправка сигналов скриптам Оболочка bash позволяет вам отправлять скриптам сигналы, пользуясь комбинациями клавиш на клавиатуре. Это оказывается очень кстати если нужно временно остановить выполняющийся скрипт или завершить его работу. Завершение работы процесса Комбинация клавиш CTRL + C генерирует сигнал SIGINT и отправляет его всем процессам, выполняющимся в оболочке, что приводит к завершению их работы. Выполним в оболочке такую команду
$ sleep 100 После этого завершим её работу комбинацией клавиш CTRL + C. Завершение работы процесса с клавиатуры Временная остановка процесса Комбинация клавиш CTRL + Z позволяет сгенерировать сигнал SIGTSTP, который приостанавливает работу процесса, ноне завершает его выполнение. Такой процесс остаётся в памяти, его работу можно возобновить. Выполним в оболочке команду
$ sleep 100 И временно остановим её комбинацией клавиш CTRL + Z. Приостановка процесса Число в квадратных скобках — это номер задания, который оболочка назначает процессу. Оболочка рассматривает процессы, выполняющиеся в ней, как задания с уникальными номерами. Первому процессу назначается номер 1, второму — 2, итак далее. Если вы приостановите задание, привязанное к оболочке, и попытаетесь выйти из не, bash выдаст предупреждение.

55 Просмотреть приостановленные задания можно такой командой 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 на клавиатуре.

56 Перехват сигналов Каждый раз, когда вы нажимаете клавиши 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.

57 Модификация перехваченных сигналов и отмена перехвата Для модификации перехваченных скриптом сигналов можно выполнить команду 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

58 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 сработала обычным образом, завершив работу скрипта.

59 Выполнение сценариев командной строки в фоновом режиме Иногда скриптам требуется немало времени для выполнения некоей задачи. При этом вам может понадобиться возможность нормально работать в командной строке, не дожидаясь завершения скрипта. Реализовать это не так ужи сложно. Если вы видели список процессов, выводимый командой ps, вы могли заметить процессы, которые выполняются в фоне и не привязаны к терминалу. Напишем такой скрипт
#!/bin/bash count=1 while [ $count -le 10 ] do sleep 1 count=$(( $count + 1 )) done Запустим его, указав после имени символ амперсанда (&):
$ ./myscipt & Это приведёт к тому, что он будет запущен как фоновый процесс. Запуск скрипта в фоновом режиме Скрипт будет запущен в фоновом процессе, в терминал выведется его идентификатора когда его выполнение завершится, вы увидите сообщение об этом. Обратите внимание на то, что хотя скрипт выполняется в фоне, он продолжает использовать терминал для вывода сообщений в STDOUT и STDERR, то есть, выводимый им текст или сообщения об ошибках можно будет увидеть в терминале. Список процессов

60 При таком подходе, если выйти из терминала, скрипт, выполняющийся в фоне, также завершит работу. Что если нужно, чтобы скрипт продолжал работать и после закрытия терминала Выполнение скриптов, не завершающих работу при закрытии терминала Скрипты можно выполнять в фоновых процессах даже после выхода из терминальной сессии. Для этого можно воспользоваться командой nohup. Эта команда позволяет запустить программу, блокируя сигналы SIGHUP, отправляемые процессу. В результате процесс будет исполняться даже при выходе из терминала, в котором он был запущен. Применим эту методику при запуске нашего скрипта nohup ./myscript & Вот что будет выведено в терминал. Команда nohup Команда nohup отвязывает процесс от терминала. Это означает, что процесс потеряет ссылки на
STDOUT и STDERR. Для того, чтобы не потерять данные, выводимые скриптом, nohup автоматически перенаправляет сообщения, поступающие в STDOUT ив, в файл nohup.out. Обратите внимание на то, что при запуске нескольких скриптов из одной и той же директории то, что они выводят, попадёт в один файл nohup.out. Просмотр заданий Команда jobs позволяет просматривать текущие задания, которые выполняются в оболочке. Напишем такой скрипт
#!/bin/bash count=1 while [ $count -le 10 ] do echo "Loop #$count" sleep 10 count=$(( $count + 1 )) done Запустим его
$ ./myscript

61 И временно остановим комбинацией клавиш CTRL + Z. Запуски приостановка скрипта Запустим тот же скрипт в фоновом режиме, при этом перенаправим вывод скрипта в файл так, чтобы он ничего не выводил на экране
$ ./myscript > outfile & Выполнив теперь команду jobs, мы увидим сведения как о приостановленном скрипте, таки о том, который работает в фоне. Получение сведений о скриптах Ключ -l при вызове команды jobs указывает на то, что нам нужны сведения об ID процессов. Перезапуск приостановленных заданий Для того, чтобы перезапустить скрипт в фоновом режиме, можно воспользоваться командой bg. Запустим скрипт
$ ./myscript
Нажмём CTRL + Z, что временно остановит его выполнение. Выполним следующую команду
$ bg Команда bg Теперь скрипт выполняется в фоновом режиме.

62 Если у вас имеется несколько приостановленных заданий, для перезапуска конкретного задания команде bg можно передать его номер. Для перезапуска задания в обычном режиме воспользуйтесь командой fg:
$ fg 1 Планирование запуска скриптов

Linux предоставляет пару способов запуска скриптов в заданное время. Это команда 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

63 Список заданий, ожидающих выполнения Удаление заданий, ожидающих выполнения Удалить задание, ожидающее выполнения, позволяет команда atrm. При её вызове указывают номер задания
$ atrm 18 Удаление задания Запуск скриптов по расписанию Планирование однократного запуска скриптов с использованием команды at способно облегчить жизнь во многих ситуациях. Но как быть, если нужно, чтобы скрипт выполнялся водно и тоже время ежедневно, или разв неделю, или разв месяц В Linux имеется утилита crontab, позволяющая планировать запуск скриптов, которые нужно выполнять регулярно.
Crontab выполняется в фоне и, основываясь на данных в так называемых таблицах, запускает задания по расписанию. Для того, чтобы просмотреть существующую таблицу заданий cron, воспользуйтесь такой командой
$ crontab –l При планировании запуска скрипта по расписанию crontab принимает данные о том, когда нужно выполнить задание, в таком формате минута, час, день месяца, месяц, день недели. Например, если надо, чтобы некий скрипт с именем command выполнялся ежедневно в 10:30, этому будет соответствовать такая запись в таблице заданий
30 10 * * * command Здесь универсальный символ «*», использованный для полей, задающих день месяца, месяц и день недели, указывает на то, что cron должен выполнять команду каждый день каждого месяца в 10:30. Если, например, надо, чтобы скрипт запускался в 4:30PM каждый понедельник, понадобится создать в таблице заданий такую запись

64 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», выполните нижеприведённую команду с правами пользователя
$ 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.

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

66 скрипты, часть 6: функции и разработка библиотек Занимаясь разработкой скриптов, вы рано или поздно столкнётесь стем, что вам периодически приходится использовать одни и те же фрагменты кода. Постоянно набирать их вручную скучно, а копирование и вставка — не наш метод. Как быть Хорошо бы найти средство, которое позволяет один раз написать блок кода и, когда он понадобится снова, просто сослаться на него в скрипте. Оболочка bash предоставляет такую возможность, позволяя создавать функции. Функции bash — это именованные блоки кода, которые можно повторно использовать в скриптах. Объявление функций Функцию можно объявить так functionName {
} Или так functionName() {
} Функцию можно вызвать без аргументов и с аргументами. Использование функций Напишем скрипт, содержащий объявление функции и использующий е
#!/bin/bash function myfunc { echo "This is an example of using a function"
} count=1 while [ $count -le 3 ] do myfunc count=$(( $count + 1 )) done echo "This is the end of the loop" myfunc echo "End of the script" Здесь создана функция с именем myfunc. Для вызова функции достаточно указать её имя.

67 Результаты вызова функции Функцию можно вызывать столько раз, сколько нужно. Обратите внимание на то, что попытавшись использовать функцию до её объявления, вы столкнётесь с ошибкой. Напишем демонстрирующий это скрипт
#!/bin/bash count=1 while [ $count -le 3 ] do myfunc count=$(( $count + 1 )) done echo "This is the end of the loop" function myfunc { echo "This is an example of using a function"
} echo "End of the script" Как и ожидается, ничего хорошего после его запуска не произошло. Попытка воспользоваться функцией до её объявления Придумывая имена для функций, учитывайте то, что они должны быть уникальными, иначе проблем не избежать. Если вы переопределите ранее объявленную функцию, новая функция будет вызываться вместо старой без каких-либо уведомлений или сообщений об ошибках. Продемонстрируем это на примере
#!/bin/bash function myfunc {

68 echo "The first function definition"
} myfunc function myfunc { echo "The second function definition"
} myfunc echo "End of the script" Как видно, новая функция преспокойно затёрла старую. Переопределение функции Использование команды return Команда return позволяет задавать возвращаемый функцией целочисленный код завершения. Есть два способа работы стем, что является результатом вызова функции. Вот первый
#!/bin/bash function myfunc { read -p "Enter a value: " value echo "adding value" return $(( $value + 10 ))
} myfunc echo "The new value is $?" Команда echo вывела сумму введённого числа и числа 10. Вывод значения, возвращаемого функцией Функция myfunc добавляет 10 к числу, которое содержится в переменной $value, значение которой задаёт пользователь вовремя работы сценария. Затем она возвращает результат, используя команду return. То, что возвратила функция, выводится командой echo с использованием переменной $?.

69 Если вы выполните любую другую команду до извлечения из переменной $? значения, возвращённого функцией, это значение будет утеряно. Дело в том, что данная переменная хранит код возврата последней выполненной команды. Учтите, что максимальное число, которое может вернуть команда return — 255. Если функция должна возвращать большее число или строку, понадобится другой подход. Запись вывода функции в переменную
Ещё один способ возврата результатов работы функции заключается в записи данных, выводимых функцией, в переменную. Такой подход позволяет обойти ограничения команды return и возвращать из функции любые данные. Рассмотрим пример
#!/bin/bash function myfunc { read -p "Enter a value: " value echo $(( $value + 10 ))
} result=$( myfunc) echo "The value is $result" Вот что получится после вызова данного скрипта. Запись результатов работы функции в переменную Аргументы функций Функции bash можно воспринимать как небольшие фрагменты кода, которые позволяют экономить время и место, избавляя нас от необходимости постоянно вводить с клавиатуры или копировать одни и те же наборы команд. Однако, возможности функций гораздо шире. В частности, речь идёт о передаче им аргументов. Функции могут использовать стандартные позиционные параметры, в которые записывается то, что передаётся им при вызове. Например, имя функции хранится в параметре $0, первый переданный ей аргумент — в $1, второй — в $2, итак далее. Количество переданных функции аргументов можно узнать, обратившись к переменной $#. Если вы знакомы с третьей частью этого цикла материалов, вы не можете не заметить, что всё это очень похоже на то, как скрипты обрабатывают переданные им параметры командной строки. Аргументы передают функции, записывая их после её имени myfunc $val1 10 20

70 Вот пример, в котором функция вызывается с аргументами и занимается их обработкой
#!/bin/bash function addnum { if [ $# -eq 0 ] || [ $# -gt 2 ] then echo -1 elif [ $# -eq 1 ] then echo $(( $1 + $1 )) else echo $(( $1 + $2 )) fi
} echo -n "Adding 10 and 15: " value=$(addnum 10 15) echo $value echo -n "Adding one number: " value=$(addnum 10) echo $value echo -n "Adding no numbers: " value=$(addnum) echo $value echo -n "Adding three numbers: " value=$(addnum 10 15 20) echo $value Запустим скрипт. Вызов функции с аргументами

71 Функция addnum проверяет число переданных ей при вызове из скрипта аргументов. Если их нет, или их больше двух, функция возвращает значение -1. Если параметр всего один, она прибавляет его к нему самому и возвращает результат. Если параметров два, функция складывает их. Обратите внимание на то, что функция не может напрямую работать с параметрами, которые переданы скрипту при его запуске из командной строки. Например, напишем такой сценарий
#!/bin/bash function myfunc { echo $(( $1 + $2 ))
} if [ $# -eq 2 ] then value=$( myfunc) echo "The result is $value" else echo "Usage: myfunc a b" fi При его запуске, а точнее, при вызове объявленной в нём функции, будет выведено сообщение об ошибке. Функция не может напрямую использовать параметры, переданные сценарию Вместо этого, если в функции планируется использовать параметры, переданные скрипту при вызове из командной строки, надо передать их ей при вызове
#!/bin/bash function myfunc { echo $(( $1 + $2 ))
} if [ $# -eq 2 ] then value=$(myfunc $1 $2) echo "The result is $value"

72 else echo "Usage: myfunc a b" fi Теперь всё работает правильно. Передача функции параметров, с которыми запущен скрипт Работа с переменными в функциях Переменные, которыми мы пользуемся в сценариях, характеризуются областью видимости. Это — те места кода, из которых можно работать с этими переменными. Переменные, объявленные внутри функций, ведут себя не так, как те переменные, с которыми мы уже сталкивались. Они могут быть скрыты от других частей скриптов. Существуют два вида переменных
● Глобальные переменные.
● Локальные переменные. Глобальные переменные Глобальные переменные — это переменные, которые видны из любого места скрипта. Если вы объявили глобальную переменную в основном коде скрипта, к такой переменной можно обратиться из функции. Почти тоже самое справедливо и для глобальных переменных, объявленных в функциях. Обращаться к ним можно ив основном коде скрипта после вызова функций. По умолчанию все объявленные в скриптах переменные глобальны. Так, к переменным, объявленным за пределами функций, можно без проблем обращаться из функций
#!/bin/bash function myfunc { value=$(( $value + 10 ))
} read -p "Enter a value: " value myfunc echo "The new value is: $value" Вот что выведет этот сценарий.

73 Обращение к глобальной переменной из функции Когда переменной присваивается новое значение в функции, это новое значение не теряется когда скрипт обращается к ней после завершения работы функции. Именно это можно видеть в предыдущем примере. Что если такое поведение нас не устраивает Ответ прост — надо использовать локальные переменные. Локальные переменные Переменные, которые объявляют и используют внутри функции, могут быть объявлены локальными. Для того, чтобы это сделать, используется ключевое слово local перед именем переменной local temp=$(( $value + 5 )) Если за пределами функции есть переменная с таким же именем, это на неё не повлияет. Ключевое слово local позволяет отделить переменные, используемые внутри функции, от остальных переменных. Рассмотрим пример
#!/bin/bash function myfunc { local temp=$[ $value + 5 ] echo "The Temp from inside function is $temp"
} temp=4 myfunc echo "The temp from outside is $temp" Запустим скрипт. Локальная переменная в функции Здесь, когда мы работаем с переменной $temp внутри функции, это не влияет назначение, назначенное переменной с таким же именем за её пределами. Передача функциям массивов в качестве аргументов

74 Попробуем передать функции в качестве аргумента массив. Сразу хочется сказать, что работать такая конструкция будет неправильно
#!/bin/bash function myfunc { echo "The parameters are: $@" arr=$1 echo "The received array is ${arr[*]}"
} myarray=(1 2 3 4 5) echo "The original array is: ${myarray[*]}" myfunc $myarray Неправильный подход к передаче функциям массивов Как видно из примера, при передаче функции массива, она получит доступ лишь к его первому элементу. Для того, чтобы эту проблему решить, из массива надо извлечь имеющиеся в нём данные и передать их функции как самостоятельные аргументы. Если надо, внутри функции полученные ей аргументы можно снова собрать в массив
#!/bin/bash function myfunc { local newarray newarray=("$@") echo "The new array value is: ${newarray[*]}"
} myarray=(1 2 3 4 5) echo "The original array is ${myarray[*]}" myfunc ${myarray[*]} Запустим сценарий.

75 Сборка массива внутри функции Как видно из примера, функция собрала массив из переданных ей аргументов. Рекурсивные функции Рекурсия — это когда функция сама себя вызывает. Классический пример рекурсии — функция для вычисления факториала. Факториал числа — это произведение всех натуральных чисел от 1 до этого числа. Например, факториал 5 можно найти так
5! = 1 * 2 * 3 * 4 * 5 Если формулу вычисления факториала написать в рекурсивном виде, получится следующее x! = x * (x-1)! Этой формулой можно воспользоваться для того, чтобы написать рекурсивную функцию
#!/bin/bash function factorial { if [ $1 -eq 1 ] then echo 1 else local temp=$(( $1 - 1 )) local result=$(factorial $temp) echo $(( $result * $1 )) fi
} read -p "Enter value: " value result=$(factorial $value) echo "The factorial of $value is: $result" Проверим, верно ли работает этот скрипт.

76 Вычисление факториала Как видите, всё работает как надо. Создание и использование библиотек Итак, теперь вызнаете, как писать функции и как вызывать их в том же скрипте, где они объявлены. Что если надо использовать функцию, тот блок кода, который она собой представляет, в другом скрипте, не используя копирование и вставку Оболочка bash позволяет создавать так называемые библиотеки — файлы, содержащие функции, а затем использовать эти библиотеки в любых скриптах, где они нужны. Ключ к использованию библиотек — в команде source. Эта команда используется для подключения библиотек к скриптам. В результате функции, объявленные в библиотеке, становятся доступными в скрипте, в противном же случае функции из библиотек не будут доступны в области видимости других скриптов. У команды source есть псевдоним — оператор точка. Для того, чтобы подключить файл в скрипте, в скрипт надо добавить конструкцию такого вида
. ./myscript Предположим, что у нас имеется файл myfuncs, который содержит следующее function addnum { echo $(( $1 + $2 ))
} Это — библиотека. Воспользуемся ей в сценарии
#!/bin/bash
. ./myfuncs result=$(addnum 10 20) echo "The result is: $result" Вызовем его. Использование библиотек Только что мы использовали библиотечную функцию внутри скрипта. Всё это замечательно, но что если мы хотим вызвать функцию, объявленную в библиотеке, из командной строки Вызов функций из командной строки

77 Если вы освоили предыдущую часть из этой серии, вы, вероятно, уже догадываетесь, что функцию из библиотеки можно подключить в файле .bashrc, используя команду source. Как результат, вызывать функцию можно будет прямо из командной строки. Отредактируйте .bashrc, добавив в него такую строку (путь к файлу библиотеки в вашей системе, естественно, будет другим
. /home/likegeeks/Desktop/myfuncs Теперь функцию можно вызывать прямо из командной строки
$ addnum 10 20 Вызов функции из командной строки
Ещё приятнее то, что такая вот библиотека оказывается доступной всем дочерним процессам оболочки, то есть — ей можно пользоваться в скриптах, не заботясь о подключении к ним этой библиотеки. Тут стоит отметить, что для того, чтобы вышеприведённый пример заработал, может понадобиться выйти из системы, а потом войти снова. Кроме того, обратите внимание на то, что если имя функции из библиотеки совпадёт с именем какой-нибудь стандартной команды, вместо этой команды будет вызываться функция. Поэтому внимательно относитесь к именам функций. Итоги Функции в скриптах позволяют оформлять блоки кода и вызывать их в скриптах. А наиболее часто используемые функции стоит выделить в библиотеки, которые можно подключать к скриптам, используя оператор source. Если же среди ваших функций найдутся такие, без которых вы прямо таки жить не можете — библиотеки сними можно подключить в файле .bashrc. Это позволит удобно пользоваться ими в командной строке или в других скриптах. Главное — чтобы имена ваших функций не совпадали с именами встроенных команд. На сегодня это всё. В следующий раз поговорим об утилите sed — мощном средстве обработки строк. скрипты, часть 7: sed и обработка текстов В прошлый раз мы говорили о функциях в скриптах, в частности, о том, как вызывать их из командной строки. Наша сегодняшняя тема — весьма полезный инструмент для обработки строковых данных — утилита Linux, которая называется sed. Её часто используют для работы с текстами, имеющими вид лог-файлов, конфигурационных и других файлов. Если вы, в скриптах, каким-то образом обрабатываете данные, вам не помешает знакомство с инструментами sed и gawk. Тут мы сосредоточимся на sed и на работе с текстами, так как это — очень важный шаг в нашем путешествии по бескрайним просторам разработки скриптов.

78 Сейчас мы разберём основы работы с sed, атак же рассмотрим более трёх десятков примеров использования этого инструмента. Основы работы с sed Утилиту sed называют потоковым текстовым редактором. В интерактивных текстовых редакторах, наподобие nano, с текстами работают, используя клавиатуру, редактируя файлы, добавляя, удаляя или изменяя тексты. Sed позволяет редактировать потоки данных, основываясь на заданных разработчиком наборах правил. Вот как выглядит схема вызова этой команды
$ sed options file По умолчанию sed применяет указанные при вызове правила, выраженные в виде набора команд, к
STDIN. Это позволяет передавать данные непосредственно sed. Например, так
$ echo "This is a test" | sed 's/test/another test/' Вот что получится при выполнении этой команды. Простой пример вызова sed В данном случае sed заменяет слово «test» в строке, переданной для обработки, словами «another test». Для оформления правила обработки текста, заключённого в кавычки, используются прямые слэши. В нашем случае применена команда вида s/pattern1/pattern2/. Буква «s» — это сокращение слова «substitute», то есть — перед нами команда замены. Sed, выполняя эту команду, просмотрит переданный текст и заменит найденные в нём фрагменты (о том — какие именно, поговорим ниже, соответствующие pattern1, на pattern2. Выше приведён примитивный пример использования sed, нужный для того, чтобы ввести вас в курс дела. На самом деле, sed можно применять в гораздо более сложных сценариях обработки текстов, например — для работы с файлами. Ниже показан файл, в котором содержится фрагмент текста, и результаты его обработки такой командой
$ sed 's/test/another test' ./myfile Текстовый файл и результаты его обработки

79 Здесь применён тот же подход, который мы использовали выше, но теперь sed обрабатывает текст, хранящийся в файле. При этом, если файл достаточно велик, можно заметить, что sed обрабатывает данные порциями и выводит то, что обработано, на экран, не дожидаясь обработки всего файла.
Sed не меняет данные в обрабатываемом файле. Редактор читает файл, обрабатывает прочитанное, и отправляет то, что получилось, в STDOUT. Для того, чтобы убедиться в том, что исходный файл не изменился, достаточно, после того, как он был передан sed, открыть его. При необходимости вывод sed можно перенаправить в файл, возможно — перезаписать старый файл. Если вы знакомы с одним из предыдущих материалов этой серии, где речь идёт о перенаправлении потоков ввода и вывода, вы вполне сможете это сделать. Выполнение наборов команд при вызове sed Для выполнения нескольких действий сданными, используйте ключ -e при вызове sed. Например, вот как организовать замену двух фрагментов текста
$ sed -e 's/This/That/; s/test/another test/' ./myfile Использование ключа -e при вызове sed К каждой строке текста из файла применяются обе команды. Их нужно разделить точкой с запятой, при этом между окончанием команды и точкой с запятой не должно быть пробела. Для ввода нескольких шаблонов обработки текста при вызове sed, можно, после ввода первой одиночной кавычки, нажать Enter, после чего вводить каждое правило с новой строки, не забыв о закрывающей кавычке
$ sed -e '
> s/This/That/
> s/test/another test/' ./myfile Вот что получится после того, как команда, представленная в таком виде, будет выполнена.

80 Другой способ работы с sed Чтение команд из файла Если имеется множество команд sed, с помощью которых надо обработать текст, обычно удобнее всего предварительно записать их в файл. Для того, чтобы указать sed файл, содержащий команды, используют ключ -f: Вот содержимое файла mycommands: s/This/That/ s/test/another test/ Вызовем sed, передав редактору файл с командами и файл для обработки
$ sed -f mycommands myfile Результат при вызове такой команды аналогичен тому, который получался в предыдущих примерах. Использование файла с командами при вызове sed Флаги команды замены Внимательно посмотрите наследующий пример.
$ sed 's/test/another test/' myfile Вот что содержится в файле, и что будет получено после его обработки sed.

81 Исходный файл и результаты его обработки Команда замены нормально обрабатывает файл, состоящий из нескольких строк, но заменяются только первые вхождения искомого фрагмента текста в каждой строке. Для того, чтобы заменить все вхождения шаблона, нужно использовать соответствующий флаг. Схема записи команды замены при использовании флагов выглядит так s/pattern/replacement/flags Выполнение этой команды можно модифицировать несколькими способами.
● При передаче номера учитывается порядковый номер вхождения шаблона в строку, заменено будет именно это вхождение.
● Флаг g указывает на то, что нужно обработать все вхождения шаблона, имеющиеся в строке.
● Флаг p указывает на то, что нужно вывести содержимое исходной строки.
● Флаг вида w file указывает команде на то, что нужно записать результаты обработки текста в файл. Рассмотрим использование первого варианта команды замены, с указанием позиции заменяемого вхождения искомого фрагмента
$ sed 's/test/another test/2' myfile Вызов команды замены с указанием позиции заменяемого фрагмента Тут мы указали, в качестве флага замены, число 2. Это привело к тому, что было заменено лишь второе вхождение искомого шаблона в каждой строке. Теперь опробуем флаг глобальной замены — g:
$ sed 's/test/another test/g' myfile Как видно из результатов вывода, такая команда заменила все вхождения шаблона в тексте.

82 Глобальная замена Флаг команды замены p позволяет выводить строки, в которых найдены совпадения, при этом ключ -n, указанный при вызове sed, подавляет обычный вывод
$ sed -n 's/test/another test/p' myfile Как результат, при запуске sed в такой конфигурации на экран выводятся лишь строки (в нашем случае
— одна строка, в которых найден заданный фрагмент текста. Использование флага команды замены p Воспользуемся флагом w, который позволяет сохранить результаты обработки текста в файл
$ sed 's/test/another test/w output' myfile Сохранение результатов обработки текста в файл Хорошо видно, что входе работы команды данные выводятся в
STDOUT
, при этом обработанные строки записываются в файл, имя которого указано после w.
1   2   3   4   5   6


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