Советы по написанию bash-скриптов

Bash по-прежнему остается важным инструментом в работе системного администратора. Обычно он применяется для скриптов автоматизации и парсинга текстовой информации (да простят меня адепты Perl и Python).

Несмотря на то, что для написания действительно больших серьезных проектов Bash мало пригоден, это не означает, что скрипты можно писать «лишь бы работало». Следующие советы облегчат жизнь вам (и тем, кто будет вынужден их поддерживать).

1. Защита от неинициализованных переменных

Добавьте в самый верх своего скрипта set -u. Данное действие заставит скрипт аварийно прекратить свою работу при попытке обратиться к неинициализованной переменной. Это защитит вас от таких фатальных ошибок как здесь:
https://tjournal.ru/26508-vladelec-hostinga-udalil-dannie-1535-svoih-klientov-odnoi-strochkoi-koda
Пример:

#!/bin/bash
set -u
echo $1
exit 0
maxim@pluto:~$ ./test.sh foo
foo
maxim@pluto:~$ ./test.sh
./test.sh: line 3: $1: unbound variable
maxim@pluto:~$

2. Проверка синтаксиса скрипта

В целом, bash весьма скуден на различные тесты, поэтому при первом запуске скрипта весьма велик шанс выстрелить себе в ногу. Этот шанс можно уменьшить, если непосредственно перед тестом произвести запуск скрипта с ключом -n:

maxim@pluto:~$ bash -n myawesomescript.sh

Флаг -n исполняет скрипт без обращений к исполняемым файлам (например, /bin/rm). Если в скрипте присутствует синтаксическая ошибка, то интерпретатор оповестит вас о ее наличии до того, как вы что-то угробите.

3. Массивы

Как бы не заявляли всевозможные эксперты о скудности функционала bash связанного с работой с массивами, они по-прежнему остаются удобным и производительным способом работы с многопараметрными элементами. Особенно это удобно при работе с данными из mysql. Пример:

maxim@pluto:~$ foo=( bar qux bozo )
maxim@pluto:~$ echo ${foo[@]}
bar qux bozo
maxim@pluto:~$ echo ${foo[0]}
bar
maxim@pluto:~$ echo ${foo[1]}
qux

И не забывайте при этом про переменную окружения $IFS. Она делает работу с массивами намного более гибкой.

4. Инклюды (заголовки)

Если вы пишете несколько скриптов, использующих одинаковые функции и переменные, то без инклюдов вы серьезно усложните себе задачу по их поддержанию (и написанию). Говорить, что они делают, не буду, ограничусь советом, что в них очень удобно класть глобальные переменные, в частности коды возврата скриптов (функций). Это очень облегчает дебаг, особенно когда скриптов много и они используют общий функционал (например, тащат данные из одной БД). Небольшой пример:

include.sh:
E_FILE_NOT_FOUND=13

script.sh:
source include.sh
file=/some/file.txt
cat $file 2> /dev/null || exit $E_FILE_NOT_FOUND

maxim@pluto:~$ ./script.sh
maxim@pluto:~$ echo $?
13

Добавить комментарий