Linux. Отладка bash-скриптов

15.06.2023

Теги: BashCLILinuxОтладка

Отладка скрипта целиком

Когда скрипт ведет себя не так, как планировалось, необходимо определить, из-за чего возникли проблемы. Наиболее распространенным способом является запуск подоболочки с опцией -x, благодаря которому весь скрипт будет запущен в отладочном режиме. После того, как для каждой команды будут выполнены все необходимые подстановки и замены, но перед тем, как команда будет выполнена, в стандартный выходной поток будет выдана трассировка команды и все ее аргументы.

Допустим, мы написали небольшой скрипт для поиска строк по регулярному выражению в файле с данными

#!/bin/bash
file=$1
find=$2
cat $file | egrep -i $find
[ $? -eq 1 ] && echo "String $find not found in file $file"
$ cat unix.txt
The Unix operating system was pioneered by Ken
Thompson and Dennis Ritchie at Bell Laboratories
in the late 1960s. One of the primary goals in
the design of the Unix system was to create an
environment that promoted efficient program
development.

И пробуем его запустить, по ошибке пропуская второй параметр

$ ./search.sh unix.txt
Использование: grep [ПАРАМЕТР]… ШАБЛОНЫ [ФАЙЛ]…
Запустите «grep --help» для получения более подробного описания.

Не очень понятно, что случилось. Давайте теперь запустим скрипт в режиме отладки.

$ bash -x search.sh unix.txt 
+ file=unix.txt
+ find=
+ egrep -i
+ cat unix.txt
Использование: grep [ПАРАМЕТР]… ШАБЛОНЫ [ФАЙЛ]…
Запустите «grep --help» для получения более подробного описания.

Каждая команда, перед ее выполнением, выводится в консоль. Мы видим, что переменной file было присвоено значение unix.txt, переменная find осталась пустой, а утилита egrep не получила строку регулярного выражения для поиска.

Пробуем запустить еще раз — на это раз с двумя параметрами

$ bash -x search.sh unix.txt 'unix'
+ file=unix.txt
+ find=unix
+ egrep -i unix
+ cat unix.txt
The Unix operating system was pioneered by Ken
the design of the Unix system was to create an

Отладка скрипта по частям

С помощью встроенной команды set можно запускать в отладочном режиме только подозрительные части скрипта. В одном скрипте можно включать и выключать отладочный режим столько раз, сколько это необходимо.

#!/bin/bash
file=$1
find=$2
set -x
cat $file | egrep -i $find
set +x
[ $? -eq 1 ] && echo "String $find not found in file $file"

Пробуем запустить скрипт, опять пропуская второй параметр

$ ./search.sh unix.txt
+ egrep -i
Использование: grep [ПАРАМЕТР]… ШАБЛОНЫ [ФАЙЛ]…
Запустите «grep --help» для получения более подробного описания.
+ cat unix.txt

Видим, что утилита egrep не получила строку регулярного выражения для поиска.

Поиск синтаксических ошибок

При написании скрипта могут быть допущены ошибки — но это легко проверить. Для примера, в скрипте пропущена закрывающая кавычка для команды echo.

$ cat search.sh
#!/bin/bash
echo 'Search string in file
file=$1
find=$2
cat $file | egrep -i $find
[ $? -eq 1 ] && echo "String $find not found in file $file"
$ bash -n search.sh
search.sh: строка 2: неожиданный конец файла во время поиска «'»
search.sh: строка 7: синтаксическая ошибка: неожиданный конец файла

Bash не будет выполянить скрипт, а только проверит на предмет наличия синтаксических ошибок.

Многословный режим запуска

Скрипт может быть запущен в verbose mode — это значит, что bash будет выводить каждую команду перед ее выполнением.

#!/bin/bash
file=$1
find=$2
cat $file | egrep -i $find
[ $? -eq 1 ] && echo "String $find not found in file $file"
$ bash -v search.sh unix.txt 'unix'
#!/bin/bash
file=$1
find=$2
cat $file | egrep -i $find
The Unix operating system was pioneered by Ken
the design of the Unix system was to create an
[ $? -eq 1 ] && echo "String $find not found in file $file"

Отладка с помощью ShellCheck

ShellCheck — это статический анализатор кода, который написан на Haskell. Он помогает искать ошибки в скриптах и дает полезные советы по улучшению кода.

$ sudo apt install shellcheck

Допустим, у нас есть простой скрипт бэкапа — давайте запустим ShellCheck и посмотрим, что он нам посоветует.

#!/bin/bash

SOURCE=/home/evgeniy/data
BACKUP=/home/evgeniy/backup
COUNT=30 # кол-во бэкапов

rm -rf ${BACKUP}/backup-${COUNT}
for (( i = $COUNT; i > 1; i-- )) ; do
    mv ${BACKUP}/backup-$((i - 1)) ${BACKUP}/backup-${i}
done

rsync --archive --link-dest=../backup-2 ${SOURCE}/ ${BACKUP}/backup-1
$ shellcheck backup.sh 
In backup.sh line 7:
for (( i = $COUNT; i > 1; i-- )) ; do
           ^----^ SC2004 (style): $/${} is unnecessary on arithmetic variables.

For more information:
  https://www.shellcheck.net/wiki/SC2004 -- $/${} is unnecessary on arithmeti...

Внутри ((...)) можно обращаться к переменным без использования знака $. Ошибок нет, но мы получили совет по улучшению скрипта.

Быстрое завершение при ошибке

Очень важно реагировать на ошибки, как только они возникают, и быстро прекращать выполнение. Ничего не может быть хуже, чем продолжать выполнение команды ниже, когда переменная $dirname не определена.

rm -rf ${dirname}/*

Для предотвращения таких случаев можно использовать встроенную команду set.

#!/bin/bash
set -o errexit
set -o nounset
set -o pipefail

rm -rf ${dirname}/*

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

#!/bin/bash
set -o errexit
set -o nounset
set -o pipefail

rmdir '/directory/not/exists' || echo 'Ошибка удаления директории, скрипт продолжит работу'
#!/bin/bash
set -o errexit
set -o nounset
set -o pipefail

if ! rmdir '/directory/not/exists'; then
    echo 'Ошибка удаления директории, скрипт продолжит работу'
fi

Поиск: Bash • CLI • Linux • Отладка

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.