DEBUG trap - как Bash выполняет код перед каждой командой
В Bash есть специальный DEBUG trap, который позволяет выполнить собственный код непосредственно перед выполнением команды.
Это удобно не только для отладки. Через него можно посмотреть, какие команды реально выполняет скрипт, с какими аргументами и в каком контексте.
▪️Самый простой пример
trap 'echo "CMD: $BASH_COMMAND"' DEBUG
echo "hello"
mkdir /tmp/test
rm -rf /tmp/test
Перед каждой командой Bash вызовет trap:
CMD: echo "hello"
CMD: mkdir /tmp/test
CMD: rm -rf /tmp/test
$BASH_COMMAND содержит команду, которую Bash собирается выполнить.
▪️Можно добавить PID и функцию
trap 'printf "[%s] %s: %s\n" "$$" "${FUNCNAME[1]:-main}" "$BASH_COMMAND"' DEBUG
Теперь при выполнении функций можно получить что-то вроде:
[4217] main: prepare
[4217] deploy: mkdir -p /srv/app
[4217] deploy: cp app.conf /srv/app/
Это уже превращается в простой трассировщик Bash-скрипта.
▪️Но DEBUG не означает буквально «перед каждой строкой»
Trap срабатывает перед выполнением простых команд, for, case, некоторых условных конструкций и других элементов shell execution.
Поведение также зависит от того, включено ли наследование trap внутри функций и subshell.
Например:
trap 'echo "DEBUG: $BASH_COMMAND"' DEBUG
foo() {
echo "inside"
}
foo
Чтобы DEBUG распространялся внутрь функций, часто используют:
set -T
или:
shopt -s functrace
▪️У trap есть интересный побочный эффект
Сам код внутри DEBUG тоже выполняется Bash, поэтому слишком сложный обработчик может сам стать источником неожиданных эффектов.
Для диагностики лучше держать его простым:
trap 'printf "%s\n" "$BASH_COMMAND" >> /tmp/bash-debug.log' DEBUG
А после диагностики обязательно убрать:
trap - DEBUG
▪️Практический сценарий
Есть большой deployment-скрипт, который запускает десятки функций и команд. Лог показывает только:
deployment failed
Вместо того чтобы расставлять echo по всему скрипту, временно включаем:
trap 'printf "[%s] %s\n" "$SECONDS" "$BASH_COMMAND"' DEBUG
и получаем последовательность реально выполнявшихся команд.
Важно: DEBUG предназначен прежде всего для трассировки. Для полноценного production-аудита он неудобен: trap может влиять на поведение скрипта и генерировать очень много вывода.
BashTex 📱 #bash #utils
В Bash есть специальный DEBUG trap, который позволяет выполнить собственный код непосредственно перед выполнением команды.
Это удобно не только для отладки. Через него можно посмотреть, какие команды реально выполняет скрипт, с какими аргументами и в каком контексте.
▪️Самый простой пример
trap 'echo "CMD: $BASH_COMMAND"' DEBUG
echo "hello"
mkdir /tmp/test
rm -rf /tmp/test
Перед каждой командой Bash вызовет trap:
CMD: echo "hello"
CMD: mkdir /tmp/test
CMD: rm -rf /tmp/test
$BASH_COMMAND содержит команду, которую Bash собирается выполнить.
▪️Можно добавить PID и функцию
trap 'printf "[%s] %s: %s\n" "$$" "${FUNCNAME[1]:-main}" "$BASH_COMMAND"' DEBUG
Теперь при выполнении функций можно получить что-то вроде:
[4217] main: prepare
[4217] deploy: mkdir -p /srv/app
[4217] deploy: cp app.conf /srv/app/
Это уже превращается в простой трассировщик Bash-скрипта.
▪️Но DEBUG не означает буквально «перед каждой строкой»
Trap срабатывает перед выполнением простых команд, for, case, некоторых условных конструкций и других элементов shell execution.
Поведение также зависит от того, включено ли наследование trap внутри функций и subshell.
Например:
trap 'echo "DEBUG: $BASH_COMMAND"' DEBUG
foo() {
echo "inside"
}
foo
Чтобы DEBUG распространялся внутрь функций, часто используют:
set -T
или:
shopt -s functrace
▪️У trap есть интересный побочный эффект
Сам код внутри DEBUG тоже выполняется Bash, поэтому слишком сложный обработчик может сам стать источником неожиданных эффектов.
Для диагностики лучше держать его простым:
trap 'printf "%s\n" "$BASH_COMMAND" >> /tmp/bash-debug.log' DEBUG
А после диагностики обязательно убрать:
trap - DEBUG
▪️Практический сценарий
Есть большой deployment-скрипт, который запускает десятки функций и команд. Лог показывает только:
deployment failed
Вместо того чтобы расставлять echo по всему скрипту, временно включаем:
trap 'printf "[%s] %s\n" "$SECONDS" "$BASH_COMMAND"' DEBUG
и получаем последовательность реально выполнявшихся команд.
Важно: DEBUG предназначен прежде всего для трассировки. Для полноценного production-аудита он неудобен: trap может влиять на поведение скрипта и генерировать очень много вывода.
BashTex 📱 #bash #utils