fbpx
linux
10

Отладка Bash скриптов

5
(1)

В shell оболочке Linux есть настройки, чтобы сделать отладку Bash скриптов и вашу повседневную работу системным администратором Linux проще.

В этой статье вы узнаете несколько полезных способов отладки Bash скриптов:

  • традиционные методы;
  • использование опции xtrace;
  • использование других параметров Bash;
  • использование ловушки.

"Самый эффективный инструмент отладки — тщательное продумывание в сочетании с разумно размещёнными командами вывода на экран," - Брайан Керниган, "Unix для начинающих" (1979).

Если вы еще мало знакомы с Linux, то рекомендую начать с чат-бота.

Требования к программному обеспечению и условные обозначения

Категория Требования и условные обозначения
Операционная система Любой дистрибутив GNU/Linux
Программа GNU Bash
Условные обозначения # - требует, чтобы указанные команды Linux выполнялись с правами root, либо из-под пользователя root, либо с помощью команды sudo; $ - требует, чтобы указанные команды Linux выполнялись из-под обычного непривилегированного пользователя

Использование традиционных методов

Как это часто бывает, отладка кода может быть сложной, даже если ошибки просты и очевидны. Обычно, программисты для помощи используют такие инструменты, как отладчики и подсветка синтаксиса в редакторах. К счастью, это актуально и при написании Bash скриптов. Простая подсветка синтаксиса позволит вам поймать ошибки при написании кода, откладывая на потом трудозатратную задачу их поиска.

Некоторые языки программирования поставляются совместно со средами отладки, такими как gcc и gdb, которые позволяют выполнять код пошагово, установить точки останова, изучить состояние всего в этих точках и многое другое.

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

$ echo "function_name(): value of \\$var is ${var}"

Использование параметра Bash xtrace

Обычно, при написании shell скриптов программная логика короткая и часто содержится в одном файле. Итак, есть несколько встроенных возможностей отладки Bash скриптов, которые мы можем использовать, чтобы увидеть, что происходит не так. Вероятно, первый, приходящий на ум, вариант, также, самый полезный - xtrace. Его можно применить к скрипту Bash путем вызова с параметром -x.

$ bash -x

Эта команда сообщает Bash показать нам, как выглядит каждое утверждение после оценки, непосредственно перед его выполнением. Сначала, давайте сравним параметр -x с его противоположностью -v, который показывает каждую строку, прежде чем она будет выполнена, а не после. Опции могут быть объединены, и с помощью как -x, так и -v можно увидеть, как выглядят операторы до и после подстановки переменных.

Способы отладки Bash скриптов. Установка параметров x и v в терминале Установка параметров x и v в терминале

Обратите внимание, что использование параметров -x и -v вместе позволяет увидеть оригинал инструкции if перед раскрытием переменной $USER благодаря параметру -v. Также, мы видим на строке, начинающейся со знака плюс, как выглядит оператор после подстановки, которая показывает нам фактические значения, сравниваемые внутри оператора if. Это может быть весьма полезным в более сложных примерах.

Использование других параметров для отладки Bash скриптов

Опции для отладки Bash скриптов отключены по умолчанию, но после их включения с помощью команды set они остаются включенными до явного отключения. Если вы не уверены, какие опции включены, можно проверить переменную $-, чтобы увидеть текущее состояние всех переменных.

$ echo $-
himBHs
$ set -xv && echo $-
himvxBHs

Есть еще один полезный ключ для отладки Bash скриптов, который мы можем использовать, чтобы помочь нам найти переменные, на которые ссылаются без какого-либо набора значений. Это ключ -u, и как и -x и -v он также может использоваться в терминале, как мы видим в следующем примере:
Установка параметра u в терминале

Мы ошибочно присвоили значение 7 переменной с именем «level», затем попытались повторить переменную с именем «score», что просто не привело к выводу на экран. Абсолютно никакой отладочной информации не было дано. Установка параметра -u позволяет увидеть конкретное сообщение об ошибке «score: не заданы границы переменной», которое указывает на то, что именно пошло не так.

Мы можем использовать эти опции в коротких Bash скриптах, чтобы получить отладочную информацию для выявления проблем, которые в противном случае не вызывают обратную связь от интерпретатора Bash. Давайте рассмотрим пару примеров.

#!/bin/bash

read -p "Path to be added: " $path

if [ "$path" = "/home/mike/bin" ]; then
    echo $path >> $PATH
    echo "new path: $PATH"
else
    echo "did not modify PATH"
fi

Написание bash скрипта в nano

Использование параметра <code>x</code> при запуске Bash скрипта

В приведенном выше примере мы выполняем Bash скрипт addpath.sh обычным образом, и он просто не изменяет наш PATH. Это не дает нам никаких указаний на то, почему были допущены ошибки. Повторный запуск с помощью опции -x ясно показывает, что левая часть сравнения является пустой строкой. $path - пустая строка, потому что мы случайно поставили знак доллара перед «path» в нашем операторе чтения. Иногда мы смотрим прямо на такую ошибку, и она не выглядит как ошибка, пока мы не получим подсказку и не подумаем: «Почему $path расценивается как пустая строка?»

Глядя на следующий пример, мы также не получаем указания на ошибку от интерпретатора. Мы получаем только одно напечатанное значение вместо двух. Это не та ошибка, которая остановит выполнение скрипта, поэтому нам остается просто удивляться, не получая никаких подсказок. Используя переключатель -u, мы немедленно получаем уведомление о том, что наша переменная j не привязана к значению. Таким образом, эти опции сохраняют наше время, когда мы совершаем ошибки, которые не приводят к фактическим ошибкам с точки зрения интерпретатора Bash.

#!/bin/bash

for i in 1 2 3
do
    echo $i $j
done

count.sh

Использование параметра <code>u</code> при запуске скрипта из терминала

Вы, конечно, думаете, что это все звучит хорошо, но нам редко нужна помощь в отладке Bash скриптов, написанных как в однострочники в командной строке или в коротких скриптах, подобных этим. Мы, обычно, боремся с отладкой, когда имеем дело с более длинными и сложными скриптами, и нам редко нужно задавать эти параметры и оставлять их установленными во время выполнения нескольких сценариев. Установка параметров -xv и последующий запуск более сложного сценария часто добавляет путаницу, удваивая или утраивая количество генерируемых выходных данных.

К счастью, мы можем использовать эти опции в более точном месте, поместив их внутрь наших скриптов. Вместо явного вызова оболочки Bash с опцией из командной строки, можно задать опцию, добавив ее в строку shebang (приме. перев.: последовательность из двух символов: решётки и восклицательного знака "#!" в начале файла скрипта).

#!/bin/bash -x

Таким образом будет установлен параметр -x для всего файла или до тех пор, пока он не будет отменен во время выполнения скрипта, что позволит просто запустить скрипт, введя имя файла вместо передачи его в Bash в качестве параметра. Однако, длинный скрипт или скрипт, который имеет много выходных данных, все равно станет громоздким, используя эту технику, так что давайте посмотрим на более конкретный способ использования параметров.

Для более целенаправленного подхода окружайте только подозрительные блоки кода нужными опциями. Этот подход отлично подходит для скриптов, которые генерируют меню или подробные выходные данные, и он выполняется с помощью ключевого слова set с плюсом или минусом еще раз.

#!/bin/bash

read -p "Path to be added: " $path

set -xv
if [ "$path" = "/home/mike/bin" ]; then
    echo $path >> $PATH
    echo "new path: $PATH"
else
    echo "did not modify PATH"
fi
set +xv

addpath.sh

Перенос параметров вокруг блока кода в скрипте

Мы окружили параметром только подозрительные блоки кода, чтобы уменьшить выводимую информацию. Обратите внимание, что мы включаем наши опции только для блока кода, содержащего наш оператор if-then-else, а затем отключаем опции в конце подозрительного блока. Мы можем включать и выключать эти параметры несколько раз в одном скрипте, если мы не можем сузить подозрительные области, или если мы хотим оценить состояние переменных в различных точках по мере прохождения через скрипт. Нет необходимости отключать опцию, если мы хотим, чтобы она продолжалась на оставшуюся часть выполнения скрипта.

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

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

Последнее, что следует упомянуть о параметрах отладки Bash скриптов, это то, что опция глоббинга файлов также существует и устанавливается с помощью -f. Установка этого параметра отключит глоббинг (расширение подстановочных знаков для создания имен файлов), пока он включен. Этот параметр -f может быть переключателем, используемым в командной строке с bash, после shebang в файле или, как в этом примере, для окружения блока кода.

#!/bin/bash

echo "with -f turned off"
ls *

echo "with -f turned on"
set -f
ls *
set +f

fileglobbing.sh

Использование параметра <code>f</code> для включения и отключения файлглоббинга

Как использовать ловушку для отладки Bash скриптов

Есть более вовлеченные методы, которые стоит рассмотреть, если ваши скрипты сложны, включая использование функции утверждения, как упоминалось ранее. Одним из таких методов является использование ловушки. Shell скрипты позволяют нам ловить сигналы и реагировать на них.

Простой, но полезный пример, который можно использовать в сценариях Bash, - ловушка на EXIT.

#!/bin/bash

trap 'echo score is $score, status is $status' EXIT

if [ -z $1 ]; then
    status="default"
else
    status=$1
fi

score=0
if [ ${USER} = 'superman' ]; then
    score=99
elif [ $# -gt 1 ]; then
    score=$2
fi

trap.sh

Использование ловушки EXIT как помощь при отладке скриптов

Как вы можете видеть, просто выдать текущие значения переменных на экран может быть полезно, чтобы показать, где ваша логика не работает. Очевидно, что сигнал EXIT не требует формирования явного оператора exit; в этом случае оператор echo выполняется при достижении конца сценария.

Другая полезная ловушка для использования со скриптами Bash - DEBUG. Она выполняется после каждого оператора, поэтому DEBUG можно использовать как грубый способ отображения значений переменных на каждом шаге выполнения скрипта.

#!/bin/bash

trap 'echo "line ${LINENO}: score is $score"' DEBUG

score=0

if [ "${USER}" = "mike" ]; then
    let "score += 1"
fi

let "score += 1"

if [ "$1" = "7" ]; then
    score=7
fi
exit 0

score.sh

Использование ловушки DEBUG для помощи в отладке скриптов

Заключение

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

Насколько публикация полезна?

Нажмите на звезду, чтобы оценить!

Средняя оценка 5 / 5. Количество оценок: 1

Оценок пока нет. Поставьте оценку первым.

Сожалеем, что вы поставили низкую оценку!

Позвольте нам стать лучше!

Расскажите, как нам стать лучше?

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Заполните поле
Заполните поле
Пожалуйста, введите корректный адрес email.
Вы должны согласиться с условиями для продолжения

Читают сейчас
Меню

Попробуй курс Linux и DevOPS