Основы BASH. Часть 1
Безусловно, все те кто общается с ОС Linux хоть раз да имели дело(во всяком случае слышали точно) с командной оболочкой BASH. Но BASH не только командная оболочка, это еще и превосходный скриптовый язык программирования. Цель этой статьи — познакомить поближе юзеров с bash, рассказать про синтаксис, основные приемы и фишки языка, для того чтобы даже обычный пользователь смог быстренько написать простой скрипт для выполнения ежедневной(-недельной, -месячной) рутинной работы или, скажем, «на коленке» наваять скриптик для бэкапа директории.
Введение
BASH — Bourne-Again SHell (что может переводится как «перерожденный шел», или «Снова шел Борна(создатель sh)»), самый популярный командный интерпретатор в юниксоподобных системах, в особенности в GNU/Linux. Ниже приведу ряд встроенных команд, которые мы будем использовать для создания своих скриптов.
- break выход из цикла for, while или until
- continue выполнение следующей итерации цикла for, while или until
- echo вывод аргументов, разделенных пробелами, на стандартное устройство вывода
- exit выход из оболочки
- export отмечает аргументы как переменные для передачи в дочерние процессы в среде
- hash запоминает полные имена путей команд, указанных в качестве аргументов, чтобы не искать их при следующем обращении
- kill посылает сигнал завершения процессу
- pwd выводит текущий рабочий каталог
- read читает строку из ввода оболочки и использует ее для присвоения значений указанным переменным.\
- return заставляет функцию оболочки выйти с указанным значением
- shift перемещает позиционные параметры налево
- test вычисляет условное выражение
- times выводит имя пользователя и системное время, использованное оболочкой и ее потомками
- trap указывает команды, которые должны выполняться при получении оболочкой сигнала
- unset вызывает уничтожение переменных оболочки
- wait ждет выхода из дочернего процесса и сообщает выходное состояние.
И конечно же кроме встроенных команд мы будем использовать целую кучу внешних, отдельных команд-программ, с которыми мы познакомимся уже в процессе
Что необходимо знать с самого начала
1. Любой bash-скрипт должен начинаться со строки:
#!/bin/bash
в этой строке после #! указывается путь к bash-интерпретатору, поэтому если он у вас установлен в другом месте(где, вы можете узнать набрав whereis bash) поменяйте её на ваш путь. 2. Коментарии начинаются с символа # (кроме первой строки). 3. В bash переменные не имеют типа(о них речь пойдет ниже)
Переменные и параметры скрипта
Приведу как пример небольшой пример, который мы разберем:
#!/bin/bash #указываем где у нас хранится bash-интерпретатор parametr1=$1#присваиваем переменной parametr1 значение первого параметра скриптаscript_name=$0#присваиваем переменной script_name значение имени скриптаecho"Вы запустили скрипт с именем $script_nameи параметром $parametr1"# команда echo выводит определенную строку, обращение к переменным осуществляется через $имя_переменной.echo'Вы запустили скрипт с именем $script_name и параметром $parametr1'# здесь мы видим другие кавычки, разница в том, что в одинарных кавычках не происходит подстановки переменных.exit0#Выход с кодом 0 (удачное завершение работы скрипта)
Результат выполнения скрипта:
ite@ite-desktop:~$ ./test.sh qwerty Вы запустили скрипт с именем ./test.sh и параметром qwerty Вы запустили скрипт с именем $script_name и параметром $parametr1
После того как мы познакомились как использовать переменные и передавать скрипту параметры, время познакомиться с зарезервированными переменными:
$DIRSTACK - содержимое вершины стека каталогов $EDITOR - текстовый редактор по умолчанию $EUID - Эффективный UID. Если вы использовали программу su для выполнения команд от другого пользователя, то эта переменная содержит UID этого пользователя, в то время как... $UID - ...содержит реальный идентификатор, который устанавливается только при логине. $FUNCNAME - имя текущей функции в скрипте. $GROUPS - массив групп к которым принадлежит текущий пользователь $HOME - домашний каталог пользователя $HOSTNAME - ваш hostname $HOSTTYPE - архитектура машины. $LC_CTYPE - внутренняя переменная, котороя определяет кодировку символов $OLDPWD - прежний рабочий каталог $OSTYPE - тип ОС $PATH - путь поиска программ $PPID - идентификатор родительского процесса $SECONDS - время работы скрипта(в сек.) $# - общее количество параметров переданных скрипту $* - все аргументы переданыне скрипту(выводятся в строку) $@ - тоже самое, что и предыдущий, но параметры выводятся в столбик $! - PID последнего запущенного в фоне процесса $$ - PID самого скрипта
Условия
Условные операторы, думаю, знакомы практически каждому, кто хоть раз пытался на чем-то писать программы. В bash условия пишутся след. образом (как обычно на примере):
#!/bin/bashsource=$1#в переменную source засовываем первый параметр скриптаdest=$2#в переменную dest засовываем второй параметр скриптаif[["$source"-eq"$dest"]]# в ковычках указываем имена переменных для сравнения. -eq - логическое сравнение обозначающие "равны" then# если они действительно равны, то echo"Применик $destи источник $sourceодин и тот же файл!"#выводим сообщение об ошибке, т.к. $source и $dest у нас равны exit1# выходим с ошибкой (1 - код ошибки) else# если же они не равныcp$source$dest# то выполняем команду cp: копируем источник в приемник echo"Удачное копирование!"fi#обозначаем окончание условия.
Результат выполнения скрипта:
ite@ite-desktop:~$ ./primer2.sh 1 1 Применик 1 и источник 1 один и тот же файл! ite@ite-desktop:~$ ./primer2.sh 1 2 Удачное копирование!
Структура if-then-else используется следующим образом:
if <команда или набор команд возвращающих код возврата(0 или 1)> then <если выражение после if истино, то выполняется этот блок> else <если выражение после if ложно, тот этот>
В качестве команд возвращающих код возврата могут выступать структуры [[ , [ , test, (( )) или любая другая(или несколько) linux-команда.
test - используется для логического сравнения. после выражения, необходима закрывающая скобка "]" [ - синоним команды test [[ - расширенная версия "[" (начиная с версии 2.02)(как в примере), внутри которой могут быть использованы || (или), & (и). Должна иметь закрывающую скобку "]]" (( )) - математическое сравнение
для построения многоярусных условий вида:
if ... then .... else if .... then.... else ....
для краткости и читаемости кода, можно использовать структуру:
if .. then ... elif ... then ... elif ...
Условия. Множественный выбор
Если необходимо сравнивать какоую-то одну переменную с большим количеством параметров, то целесообразней использовать оператор case.
#!/bin/bash echo "Выберите редатор для запуска:" echo "1 Запуск программы nano" echo "2 Запуск программы vi" echo "3 Запуск программы emacs" echo "4 Выход" read doing #здесь мы читаем в переменную $doing со стандартного ввода case $doing in 1) /usr/bin/nano # если $doing содержит 1, то запустить nano ;; 2) /usr/bin/vi # если $doing содержит 2, то запустить vi ;; 3) /usr/bin/emacs # если $doing содержит 3, то запустить emacs ;; 4) exit 0 ;; *) #если введено с клавиатуры то, что в case не описывается, выполнять следующее: echo "Введено неправильное действие" esac #окончание оператора case.
Результат работы:
$ ./menu2.sh Выберите редатор для запуска: 1 Запуск программы nano 2 Запуск программы vi 3 Запуск программы emacs 4 Выход
После выбор цифры и нажатия Enter запуститься тот редактор, который вы выбрали(если конечно все пути указаны правильно, и у вас установлены эти редакторы :) )
Прведу список логических операторв, которые используются для конструкции if-then-else-fi:
-z # строка пуста -n # строка не пуста =, (==) # строки равны != # строки неравны -eq # равно -ne # неравно -lt,(< ) # меньше -le,(<=) # меньше или равно -gt,(>) #больше -ge,(>=) #больше или равно ! #отрицание логического выражения -a,(&&) #логическое «И» -o,(||) # логическое «ИЛИ»
С основами языка и условиями мы разобрались, чтобы не перегружать статью, разобью её на несколько частей(допустим на 3). Во второй части разберем операторы цикла и выполнение математических операций.