При написании простых и коротких сценариев оболочки может показаться, что отлаживать скрипты в Bash проще простого. Однако сложность имеет тенденцию возрастать при обслуживании большей базы кода или при совместной работе с вашими коллегами. В таких случаях выполнение последовательных шагов по отладке скриптов имеет решающее значение для обеспечения быстрого процесса отладки.
В этом посте рассматриваются различные специальные свойства оболочки Bash и то, как вы можете использовать их для эффективной отладки скриптов.
3 типа ошибок скрипта
Отладка скрипта оболочки Bash иногда может быть утомительной. Выполнив 5 простых шагов в этом посте, вы избавите себя от некоторых серьезных головных болей.
При программировании существует три основных типа ошибок, и это остается верным в сценариях оболочки.
- Синтаксическая ошибка
Обычно синтаксические ошибки легче всего устранить в сценарии Bash. Их часто можно обнаружить без выполнения сценария оболочки. К наиболее распространенным синтаксическим ошибкам относятся:- Неправильное использование квадратных скобок в операторе If
- Неправильный синтаксис при использовании цикла Bash или массива Bash
- Неправильное использование составной команды при определении функции Bash
- Ошибка во время выполнения
Ошибка во время выполнения будет следующим уровнем ошибок. Сценарий оболочки выполняется без синтаксических ошибок, но не может надежно выполнять определенные задачи. Наиболее распространенные ошибки во время выполнения сценария оболочки включают:- Деление на ноль или использование переменной string/float в арифметическом выражении Bash
- Неверный нижний индекс при динамическом заполнении ассоциативного массива Bash
- Неправильный синтаксический анализ вывода файла или команды, например, при обработке CSV-файла в Bash или подсчете файлов в каталоге
- Запуск с неправильными разрешениями sudo или настройками tty
- Логическая ошибка
Логические ошибки часто сложнее всего устранить, поскольку они связаны с недостатками дизайна и логическими ошибками. Отладка таких ошибок может быть затруднена, если не иметь полного понимания сквозного выполнения скрипта и ожидаемого поведения. К наиболее распространенным логическим ошибкам в сценарии оболочки относятся:- Неправильное использование оператора test в условном операторе, например, using -z вместо -n в условии if
- Неправильное использование арифметического оператора, такого как умножение, вместо ввода числа
- Неправильное условие для выхода из цикла Bash, например, при использовании while цикла вместо цикла until
- Неправильное манипулирование датами Linux с разными часовыми поясами
- Отображение неправильного сообщения в командной строке или в журналах
5 шагов по отладке скрипта в Bash
Шаг 1: Используйте согласованную библиотеку отладки
Какова бы ни была цель ваших сценариев оболочки, работаете ли вы в одиночку или сотрудничаете с товарищами по команде, важно быть последовательным и систематичным в процессе отладки, чтобы быстро устранять неполадки и отлаживать сценарий оболочки.
Вы можете систематически создавать исходные файлы общей библиотеки, которая содержит все ваши настройки отладки, используя команды source и dot, но этот подход не идеален, если вы унаследовали чужую проблему и не хотите или не можете изменять исходный код.
Альтернативой является использование переменной окружения $BASH_ENV, которая используется Bash для определения файла инициализации для чтения перед выполнением скрипта. Вы можете использовать его для создания среды для целей отладки и определения конкретных параметров оболочки или отладочных ловушек.
Переменная $ENV аналогична $BASH_ENV. Она используется, когда оболочка запускается в режиме совместимости с POSIX.
### Определите среду отладки ### Filename: my-debug-env trap 'echo "$BASH_COMMAND" failed with error code $?' ERR #!/usr/bin/env bash ### пример Script ### Filename: example-debug echo "Пример Script..." bad_command &> /dev/null ### Пример вывода без debug env [andreyex@linux ~]$ ./example-debug Example Script... ### Пример вывода с помощью debug env [andreyex@linux ~]$ BASH_ENV=./my-debug-env ./example-debug Example Script... bad_command &> /dev/null failed with error code 127
На следующих шагах мы продолжим улучшать содержимое BASH_ENV скрипта инициализации ./my-debug-env. Преимущество этого метода в том, что независимо от того, какой скрипт вы собираетесь отлаживать и на каком сервере Linux вы находитесь, у вас будут согласованные настройки, ловушки и ведение журнала (если только это не переопределено самим скриптом).
Шаг 2: Проверьте, нет ли синтаксической ошибки
Обнаружение синтаксической ошибки только после выполнения сценария оболочки может привести к разочарованию, и это не идеально в случае, когда выполнение команды занимает много времени или создает множество других артефактов.
Давайте рассмотрим простую, но распространенную синтаксическую ошибку, связанную с неправильным использованием единственной квадратной скобки и пропущенным then
ключевым словом.
#!/usr/bin/env bash # Filename: ./example-syntax-error echo "Это было выполнено" if [-z "$v" ]; echo "Здесь опечатка" fi ## Output [andreyex@linux ~]$ ./example-syntax-error Это было выполнено ./test: line 12: syntax error near unexpected token `fi' ./test: line 12: `fi'
В Bash есть две опции для обнаружения синтаксических ошибок такого рода без выполнения сценария. Во-первых, с помощью опции оболочки noexec
. Во-вторых, с помощью инструмента статического анализа.
Используйте параметр оболочки noexec
Оболочка Bash предоставляет noexec
параметр оболочки, который может быть установлен либо с помощью set -o noexec
, либо с помощью set -n
. Этот параметр заставит оболочку Bash только читать команды, но не выполнять их, а также не будет выполнять присвоение переменной. Короче говоря, это базовый режим “без операции“ или “пробный запуск”.
⚠️ Как только
noexec
опция выполняетсяset
встроенной командой, любые другие команды после этого НЕ будут выполняться, включая любую следующую командуset
.
Вы можете легко включить небольшое условие и использовать переменную окружения, чтобы автоматически включить опцию noexec
проверки синтаксиса вашего скрипта. Это можно сделать непосредственно в исходном коде вашего скрипта или, что лучше, в сценарии инициализации среды отладки, my-debug-env
как упоминалось на шаге 1, используя переменную BASH_ENV
. Это может быть удобно в конвейере CI/CD перед развертыванием вашего сценария в рабочей среде.
### Определите среду отладки ### Filename: my-debug-env if [[ -v NOOP ]]; then echo "Run NOOP mode" set -o noexec # same as set -n fi trap 'echo "$BASH_COMMAND" failed with error code $?' ERR #!/usr/bin/env bash # Filename: example-syntax-error echo "Это было выполнено" if [-z "$v" ]; echo "Здесь опечатка" fi ## Output [andreyex@linux ~]$ NOOP=1 BASH_ENV=my-debug-env ./example-syntax-error Run NOOP mode ./example-syntax-error: line 6: syntax error near unexpected token `fi' ./example-syntax-error: line 6: `fi'
Теперь вы можете получить сообщение о синтаксической ошибке оболочки без выполнения какой-либо из команд в скрипте.
👉 Этот метод не сможет перехватить синтаксические ошибки в сценарии оболочки, импортированном с помощью команд source или dot, поскольку команды не будут выполняться в режиме
noexec
. Каждый скрипт следует проверять индивидуально на наличие синтаксических ошибок.
Используйте инструмент статического анализа: ShellCheck
Одна из проблем с noexec
режимом заключается в том, что он просто выводит необработанные синтаксические ошибки, которые не всегда легко интерпретировать и диагностировать. Лучшим подходом является использование инструмента статического анализа, такого как ShellCheck, который стал стандартом defacto, когда дело доходит до статического анализа скриптов Bash.
Наш предыдущий пример с синтаксической ошибкой shellcheck
предоставляет нам гораздо более понятную информацию и полезные рекомендации по исправлению ошибок.
[andreyex@linux ~]$ shellcheck ./example-syntax-error In ./example-syntax-error line 9: if [-z "$v" ]; ^-- SC1049: Did you forget the 'then' for this 'if'? ^-- SC1073: Couldn't parse this if expression. Fix to allow more checks. ^-- SC1035: You need a space after the [ and before the ]. In ./example-syntax-error line 11: fi ^-- SC1050: Expected 'then'. ^-- SC1072: Unexpected keyword/token. Fix any mentioned problems and try again. For more information: https://www.shellcheck.net/wiki/SC1035 -- You need a space after the [ and ... https://www.shellcheck.net/wiki/SC1049 -- Did you forget the 'then' for thi... https://www.shellcheck.net/wiki/SC1050 -- Expected 'then'.
Как только мы исправим эти очевидные синтаксические ошибки shellcheck
, сделаем шаг дальше и даже предоставим уведомления о неправильно назначенных переменных, которые позволят нам предотвратить некоторые возможные ошибки во время выполнения.
[andreyex@linux ~]$ shellcheck ./example-syntax-error In example-xtrace line 9: if [[ -z "$v" ]]; then ^-- SC2154: v is referenced but not assigned. For more information: https://www.shellcheck.net/wiki/SC2154 -- v is referenced but not assigned.
👉 Вы можете многое сделать с
shellcheck
, чтобы уменьшить количество ошибок в ваших скриптах оболочки bash и ускорить отладку. Обычно мы будем явно использовать следующий синтаксисshellcheck -s bash -o all -xa <your_script>
, чтобы воспользоваться всеми возможными рекомендациями (опция-o all
) и убедиться, что исходные файлы также проверены (опции-xa
).
Шаг 3: Отследите выполнение команды вашего скрипта
Еще одна полезная опция оболочки – это xtrace
опция, которую можно включить с помощью set -o xtrace
или set -x
. Когда ваш скрипт Bash выполняется в режиме трассировки, все команды и их аргументы распечатываются перед выполнением. Это полезно для отладки ошибок среды выполнения и логики в скрипте.
📎 Вы можете заменить
+
символ по умолчанию, используемый в выводеxtrace
, изменив переменную Bash Prompt $PS4.
В качестве альтернативы вы можете использовать verbose
опцию shell вместо этого, используя set -o verbose
или set -v
. Основное отличие от xtrace
заключается в том, что подробный режим отображает строки ввода оболочки только по мере их чтения. Вы не увидите аргументы, передаваемые командам, что обычно полезно при попытке отладки сценария bash. Возможно, вам будет полезно использовать оба варианта.
### Определите среду отладки ### Filename: my-debug-env if [[ -v TRACE ]]; then echo "Run TRACE mode" set -o xtrace # same as set -x fi if [[ -v NOOP ]]; then echo "Run NOOP mode" set -o noexec # same as set -n fi trap 'echo "$BASH_COMMAND" failed with error code $?' ERR #!/usr/bin/env bash # Filename: ./example-xtrace echo "Это было выполнено" v=$1 if [[ -z "${v}" ]]; then echo "\$v is empty" fi ## Output [andreyex@linux ~]$ NOOP=1 TRACE=1 BASH_ENV=my-debug-env ./example-xtrace Run TRACE mode + [[ -v NOOP ]] + echo 'Run NOOP mode' Run NOOP mode + set -o noexec [andreyex@linux ~]$ TRACE=1 BASH_ENV=my-debug-env ./example-xtrace Run TRACE mode + [[ -v NOOP ]] + echo 'Это было выполнено' Это было выполнено + [[ -z '' ]] + echo '$v is empty' $v is empty
Такой вывод трассировки хорош, но он может быстро усложнить отладку скрипта, поскольку весь вывод скрипта путается в терминале. Простым и очевидным решением является перенаправление стандартных ошибок в другой файл с помощью, например TRACE=1 ./example-xtrace 2>error.log
. Однако, если ваш скрипт использует стандартный вывод ошибок, то у вас все равно остается трассировка отладки, смешанная со стандартными ошибками.
Чтобы решить эту проблему, Bash может записать выходные данные трассировки, сгенерированные опцией xtrace
оболочки, в заданный файловый дескриптор, указанный в переменной $BASH_XTRACEFD. Это позволяет отделить вывод трассировки от стандартного вывода скрипта и стандартных сообщений об ошибках. В нашем следующем примере используется файл xtrace.out
, но вместо этого вы можете использовать перенаправление оболочки на утилиту ведения журнала, такую как logger
или syslog
.
Файловый дескриптор закрывается, когда переменная $BASH_XTRACEFD
отменяется или ей присваивается новое значение. Отмена установки $BASH_XTRACEFD
или присвоение ей пустой строки приводит к тому, что вывод трассировки отправляется со стандартной ошибкой.
⚠️ Установка
$BASH_XTRACEFD
стандартного дескриптора файла ошибки (2), а затем его отмена приведет к закрытию стандартной ошибки.
[andreyex@linux ~]$ lsof -p $$ # List all current open files ... [andreyex@linux ~]$ ls /proc/$$/fd # Use /dev/fd/ on mac 0 1 2 255 [andreyex@linux ~]$ exec 4>xtrace.out # Could be replaced by: exec 4> >(logger -t $0) [andreyex@linux ~]$ ls /proc/$$/fd 0 1 2 255 4 [andreyex@linux ~]$ BASH_XTRACEFD=4 [andreyex@linux ~]$ set -x [andreyex@linux ~]$ less xtrace.out ++ update_terminal_cwd ++ local url_path= ++ local i ch hexch LC_CTYPE=C LC_ALL= ++ (( i = 0 )) ... [andreyex@linux ~]$ set +x [andreyex@linux ~]$ unset BASH_XTRACEFD [andreyex@linux ~]$ ls /proc/$$/fd 0 1 2 255
Затем наш предыдущий пример можно обновить, чтобы использовать переменную BASH_XTRACEFD
при включенной трассировке.
### Определите среду отладки ### Filename: my-debug-env if [[ -v TRACE ]]; then echo "Run TRACE mode" exec 4>./xtrace.out # Could be replaced by: exec 4> >(logger -t $0) BASH_XTRACEFD=4 set -o xtrace # same as set -x fi if [[ -v NOOP ]]; then echo "Run NOOP mode" set -o noexec # same as set -n fi trap 'echo "$BASH_COMMAND" failed with error code $?' ERR #!/usr/bin/env bash # Filename: ./example-xtrace echo "Это было выполнено" v=$1 if [[ -z "${v}" ]]; then echo "\$v is empty" fi ## Output [andreyex@linux ~]$ TRACE=1 BASH_ENV=my-debug-env ./example-xtrace Run TRACE mode Это было выполнено $v is empty [andreyex@linux ~]$ cat xtrace.out + [[ -v NOOP ]] + echo 'Это было выполнено' + v= + [[ -z '' ]] + echo '$v is empty'
Шаг 4. Используйте расширенный режим отладки
Использование отладчика часто необходимо для понимания ошибок времени выполнения или логики в программе, это также может быть верно для большого сценария оболочки.
📎 Необходимость в отладчике также может быть серьезным предупреждением о том, что вы пишете не на том языке. Bash не всегда хорошо подходит для любой работы. Сценарии Bash должны оставаться простыми и понятными.
Оболочка Bash может запускаться в расширенном режиме отладки с помощью опции shell extdebug
, которая позволяет интерактивному отладчику Bash шаг за шагом исследовать и отлаживать ваш скрипт.
При использовании shopt -s extdebug
оболочка также автоматически включит set
встроенную опцию errtrace
и functrace
для отслеживания ошибок в функциях bash. С помощью опций errtrace
и functrace
вы получаете доступ к DEBUG
trap, RETURN
ловушке и специальным переменным BASH_ARGC
Bash, BASH_ARGV
и BASH_ARGV0
.
⚠️ Опция
extdebug
зависит от утилиты bashdb. Если она не установлена, вы получите сообщение об ошибкеwarning: cannot start debugger; debugging mode disabled
. Командаbashdb
может быть недоступна на вашей платформе и может потребовать ручной установки. В Ubuntu 20.04 вы можете использовать этот bashdb PPA, а на Mac вы можете использоватьbrew install bashdb
. Если вы используете VS codium или VS code, вы можете использовать расширение vscode-bash-debug, которое включает в себяbashdb
.
В дополнение к extdebug
опции вы можете вызвать отладчик bash непосредственно из командной строки, используя одну из приведенных ниже команд:
bashdb [options] [--] script-name [script options]
bashdb [options] -c execution-string
bash --debugger [bash-options...] script-name [script options]
👉 Если вы не хотите или не можете использовать отладчик bashdb, вы можете заменить использование
shopt -s extdebug
параметров отладки/трассировки оболочки наset -o errtrace
иset -o functrace
, которые предоставляют большую часть функциональности, описанной ниже, за исключением интерактивного пошагового отладчика.
Чтобы управлять режимом отладчика в нашем текущем примере, вы можете добавить небольшой блок my-debug-env
в сценарий запуска, который установит необходимые параметры оболочки в зависимости от того, будет установлена пользовательская переменная среды DEBUGGER
или нет.
if [[ -v DEBUGGER ]]; then shopt -s extdebug else set -o errtrace set -o functrace fi
Важно, чтобы опции errtrace
и functrace
были включены тем или иным способом, поскольку это гарантирует, что ловушки ERR
, DEBUG
RETURN
будут унаследованы заменой команд, функциями оболочки и подоболочками.
[andreyex@linux ~]$ trap 'echo "ERR trap from ${FUNCNAME:-MAIN} context."' ERR [andreyex@linux ~]$ false ERR trap from MAIN context. [andreyex@linux ~]$ fn() { false; }; fn ; echo "fn exit code is $?" ERR trap from MAIN context. fn exit code is 1 [andreyex@linux ~]$ fn() { false; true; }; fn ; echo "fn exit code is $?" fn exit code is 0 [andreyex@linux ~]$ set -o errtrace [andreyex@linux ~]$ fn() { false; true; }; fn ; echo "fn exit code is $?" ERR trap from fn context. fn exit code is 0
Наиболее распространенной командой внутри отладчика Bash, bashdb
, будет set linetrace on
печатать каждую выполненную команду, print var
чтобы отобразить текущее присвоенное значение переменной var, step n
(или s n
) перейти к следующему действию за n шагов (n = 1, если не указано) и cont
(или c
) продолжить выполнение полного сценария.
[andreyex@linux ~]$ DEBUGGER=1 BASH_ENV=my-debug-env ./example-debug param1 bash debugger, bashdb, release 5.0-1.1.2 Copyright 2002-2004, 2006-2012, 2014, 2016-2019 Rocky Bernstein This is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. (/home/jdoe/example-debug:3): 3: echo $BASH_ENV bashdb<0> set linetrace on bashdb<1> step my-debug-env (/home/jdoe/example-debug:4): 4: set -o bashdb<2> cont (/home/jdoe/example-debug:16): level 1, subshell 0, depth 0: echo "Example Script..." Example Script... (/home/jdoe/example-debug:17): level 1, subshell 0, depth 0: echo "Main BASH_ARGC=${BASH_ARGC[@]} BASH_ARGV=${BASH_ARGV[@]}" Main BASH_ARGC=1 BASH_ARGV=param1 ...
Переменные $BASH_ARGC и $BASH_ARGV представляют собой массивы, содержащие информацию о скрипте и позиционных параметрах функций. $BASH_ARGC
содержит количество параметров в каждом фрейме текущего стека вызовов выполнения bash, упорядоченных с последнего по первый вызов, в то время как $BASH_ARGV
содержит все параметры в текущем стеке вызовов выполнения bash, упорядоченные с последнего по первый вызов.
### Example Script #!/usr/bin/env bash shopt -s extdebug debug() { echo "Func: ${BASH_ARGC[@]} ${BASH_ARGV[@]}" } echo "Main: ${BASH_ARGC[@]} ${BASH_ARGV[@]}" debug c ### Example output [andreyex@linux ~]$ ./example-argdebug a b Main: 2 b a Func: 1 2 c b a
$BASH_ARGV0 идентичен специальному параметру $0
и расширяется до имени текущей оболочки или сценария оболочки. Присвоение нового значения $BASH_ARGV0
также обновит $0
специальный параметр. $BASH_ARGV0
при отмене настройки он потеряет свои специальные свойства. Эта переменная доступна начиная с версии Bash 5.
[andreyex@linux ~]$ echo $0 $BASH_ARGV0 /usr/local/bin/bash /usr/local/bin/bash
Шаг 5: предоставьте значимые журналы отладки
Наконец, подобно тому, как важно писать качественные комментарии к bash, так же важно иметь значимые журналы отладки, и есть несколько переменных среды bash, которые вы, возможно, захотите использовать для быстрой отладки вашего скрипта.
$BASH_COMMAND содержит имя команды, выполняемой в данный момент или собирающейся быть выполненной, за исключением случаев, когда оболочка выполняет команду в результате перехвата, тогда значение присваивается команде, выполненной во время перехвата. Эта переменная в основном полезна для журналов отладки или ошибок.
[andreyex@linux ~]$ trap 'echo "$BASH_COMMAND" failed with error code $?' ERR [andreyex@linux ~]$ bad_command &>/dev/null bad_command &> /dev/null failed with error code 127
$BASH_LINENO и $BASH_SOURCE являются переменными массива bash. Эти переменные часто используются для отладки и ведения журнала и работают совместно с переменной функции bash$FUNCNAME
. Переменная $BASH_SOURCE
содержит исходные имена файлов, в которых определены соответствующие имена функций оболочки в $FUNCNAME
переменной массива. Переменная $BASH_LINENO
содержит номера строк в исходных файлах, где был вызван каждый соответствующий элемент $FUNCNAME
.
$LINENO содержит номер строки в скрипте или функции оболочки, выполняемой в данный момент.
### пример script
### Filename: example-debug
#!/usr/bin/env bash
debug() {
echo "Func BASH_SOURCE: ${!BASH_SOURCE[@]} ${BASH_SOURCE[@]}"
echo "Func BASH_LINENO: ${!BASH_LINENO[@]} ${BASH_LINENO[@]}"
echo "Func FUNCNAME: ${!FUNCNAME[@]} ${FUNCNAME[@]}"
echo "Func LINENO: ${LINENO}"}echo "Example Script..."
echo "Main BASH_SOURCE: ${!BASH_SOURCE[@]} ${BASH_SOURCE[@]}"
echo "Main BASH_LINENO: ${!BASH_LINENO[@]} ${BASH_LINENO[@]}"
echo "Main FUNCNAME: ${!FUNCNAME[@]} ${FUNCNAME[@]}"
echo "Main LINENO: ${LINENO}"debug
### Example output[andreyex@linux ~]$ ./example-debug
Example Script...
Main BASH_SOURCE: 0 ./example-debug
Main BASH_LINENO: 0 0Main FUNCNAME:
Main LINENO: 13
Func BASH_SOURCE: 0 1 ./example-debug ./example-debug
Func BASH_LINENO: 0 1 12 0
Func FUNCNAME: 0 1 debug main
Func LINENO: 7
Некоторые другие переменные оболочки, которые, возможно, стоит использовать, включают в себя BASHPID
, PID
, BASH
, SHELL
, BASHOPTS
, SHELLOPTS
, POSIXLY_CORRECT
, BASH_COMPAT
. Эти переменные может быть полезно напечатать в начале или конце вывода журнала, чтобы узнать, в какой текущей среде выполняется ваш скрипт. Часто вы можете предположить, что какая-то опция оболочки включена, или обнаружить, что вы работаете в режиме совместимости, который отключает некоторые функции, которые вы ожидаете иметь.
Полный пример
На основе этих подробных шагов мы можем создать простой скрипт инициализации среды отладки Bash, который будет использоваться всякий раз, когда мы захотим отладить или профилировать скрипт bash.
👉 Не стесняйтесь изменять приведенный ниже пример, добавляя необходимый уровень отладочной информации, чтобы он соответствовал вашим потребностям.
### Определите среду отладки ### Filename: my-debug-env PS4='+[$0:$LINENO] ' if [[ -v DEBUGGER ]]; then shopt -s extdebug else set -o errtrace set -o functrace fi if [[ -v TRACE ]]; then echo "Run TRACE mode" exec 4>./xtrace.out BASH_XTRACEFD=4 set -o xtrace # same as set -x fi if [[ -v NOOP ]]; then echo "Run NOOP mode" set -o noexec # same as set -n fi debug() { echo "[ DEBUG ]| BASH_COMMAND=${BASH_COMMAND}" echo " | BASH_ARGC=${BASH_ARGC[@]} BASH_ARGV=${BASH_ARGV[@]}" echo " | BASH_SOURCE: ${!BASH_SOURCE[@]} ${BASH_SOURCE[@]}" echo " | BASH_LINENO: ${!BASH_LINENO[@]} ${BASH_LINENO[@]}" echo " | FUNCNAME: ${!FUNCNAME[@]} ${FUNCNAME[@]}" } trap 'echo ERR trap from ${FUNCNAME:-MAIN} context. $BASH_COMMAND failed with error code $?' ERR trap 'debug' DEBUG
Мы можем попробовать это с помощью простого примера скрипта.
#!/usr/bin/env bash
# Filename: ./example-xtrace
echo "Это было выполнено"
v=$1
if [[ -z "${v}" ]]; then
echo "\$v is empty"
fi
## Debug Output
[andreyex@linux ~]$ TRACE=1 BASH_ENV=my-debug-env ./example-xtrace param1
Run TRACE mode
[ DEBUG ]| BASH_COMMAND=echo "Это было выполнено"
| BASH_ARGC=1 BASH_ARGV=param1
| BASH_SOURCE: 0 1 my-debug-env ./example-xtrace
| BASH_LINENO: 0 1 3 0
| FUNCNAME: 0 1 debug main
Это было выполнено
[ DEBUG ]| BASH_COMMAND=v=$1
| BASH_ARGC=1 BASH_ARGV=param1
| BASH_SOURCE: 0 1 my-debug-env ./example-xtrace
| BASH_LINENO: 0 1 4 0
| FUNCNAME: 0 1 debug main
[ DEBUG ]| BASH_COMMAND=[[ -z "${v}" ]]
| BASH_ARGC=1 BASH_ARGV=param1
| BASH_SOURCE: 0 1 my-debug-env ./example-xtrace
| BASH_LINENO: 0 1 5 0
| FUNCNAME: 0 1 debug main
# XTRACE Logs[andreyex@linux ~]$ cat xtrace.out
+[bash:20] [[ -v NOOP ]]
+[bash:33] trap 'echo ERR trap from ${FUNCNAME:-MAIN} context. $BASH_COMMAND failed with error code $?' ERR
+[bash:34] trap debug DEBUG
++[./example-xtrace:3] debug
++[./example-xtrace:26] echo '[ DEBUG ]| BASH_COMMAND=echo "Это было выполнено"'
++[./example-xtrace:27] echo ' | BASH_ARGC=1 BASH_ARGV=param1'
++[./example-xtrace:28] echo ' | BASH_SOURCE: 0' '1 my-debug-env' ./example-xtrace
++[./example-xtrace:29] echo ' | BASH_LINENO: 0' '1 3' 0
++[./example-xtrace:30] echo ' | FUNCNAME: 0' '1 debug' main
+[./example-xtrace:3] echo 'Это было выполнено'
++[./example-xtrace:4] debug
++[./example-xtrace:26] echo '[ DEBUG ]| BASH_COMMAND=v=$1'
++[./example-xtrace:27] echo ' | BASH_ARGC=1 BASH_ARGV=param1'
++[./example-xtrace:28] echo ' | BASH_SOURCE: 0' '1 my-debug-env' ./example-xtrace
++[./example-xtrace:29] echo ' | BASH_LINENO: 0' '1 4' 0
++[./example-xtrace:30] echo ' | FUNCNAME: 0' '1 debug' main
+[./example-xtrace:4] v=param1
++[./example-xtrace:5] debug
++[./example-xtrace:26] echo '[ DEBUG ]| BASH_COMMAND=[[ -z "${v}" ]]'
++[./example-xtrace:27] echo ' | BASH_ARGC=1 BASH_ARGV=param1'
++[./example-xtrace:28] echo ' | BASH_SOURCE: 0' '1 my-debug-env' ./example-xtrace
++[./example-xtrace:29] echo ' | BASH_LINENO: 0' '1 5' 0
++[./example-xtrace:30] echo ' | FUNCNAME: 0' '1 debug' main
+[./example-xtrace:5] [[ -z param1 ]]
Используя этот подход, хотя он и является маловероятным вариантом использования, вы также можете отлаживать команды Bash из командной строки, используя опцию -c
.
[andreyex@linux ~]$ y=9
[andreyex@linux ~]$ TRACE=1 BASH_ENV=my-debug-env bash -c "x=1; y=$y; echo \$((x+y))"
Run TRACE mode
[ DEBUG ]| BASH_COMMAND=x=1
| BASH_ARGC=0 BASH_ARGV=
| BASH_SOURCE: 0 my-debug-env
| BASH_LINENO: 0 0
| FUNCNAME: 0 debug
[ DEBUG ]| BASH_COMMAND=y=9
| BASH_ARGC=0 BASH_ARGV=
| BASH_SOURCE: 0 my-debug-env
| BASH_LINENO: 0 0| FUNCNAME: 0 debug
[ DEBUG ]| BASH_COMMAND=echo $((x+y))| BASH_ARGC=0 BASH_ARGV=
| BASH_SOURCE: 0 my-debug-env
| BASH_LINENO: 0 0
| FUNCNAME: 0 debug
10[andreyex@linux ~]$ cat xtrace.out
+[bash:20] [[ -v NOOP ]]
+[bash:33] trap 'echo ERR trap from ${FUNCNAME:-MAIN} context. $BASH_COMMAND failed with error code $?' ERR
+[bash:34] trap debug DEBUG
++[bash:0] debug
++[bash:26] echo '[ DEBUG ]| BASH_COMMAND=x=1'
++[bash:27] echo ' | BASH_ARGC=0 BASH_ARGV='
++[bash:28] echo ' | BASH_SOURCE: 0 my-debug-env'
++[bash:29] echo ' | BASH_LINENO: 0 0'
++[bash:30] echo ' | FUNCNAME: 0 debug'+[bash:0] x=1++[bash:0] debug
++[bash:26] echo '[ DEBUG ]| BASH_COMMAND=y=9'
++[bash:27] echo ' | BASH_ARGC=0 BASH_ARGV='
++[bash:28] echo ' | BASH_SOURCE: 0 my-debug-env'
++[bash:29] echo ' | BASH_LINENO: 0 0'
++[bash:30] echo ' | FUNCNAME: 0 debug'+[bash:0] y=9++[bash:0] debug
++[bash:26] echo '[ DEBUG ]| BASH_COMMAND=echo $((x+y))'
++[bash:27] echo ' | BASH_ARGC=0 BASH_ARGV='
++[bash:28] echo ' | BASH_SOURCE: 0 my-debug-env'
++[bash:29] echo ' | BASH_LINENO: 0 0'
++[bash:30] echo ' | FUNCNAME: 0 debug'