set -euo pipefail сверху, set -x вокруг мутного места и ловушка DEBUG с read, чтобы останавливаться перед каждой командой. Прогнал этот набор на Ubuntu 24.04, bash 5.2. Три вещи из него ведут себя не так, как ожидаешь.Сначала то, что работает без оговорок:
# падаем на ошибке, пустой переменной и в пайпах
set -euo pipefail
pipefail не декорация: false | true без него даёт код 0, с ним 1. А set -u ловит то, до чего не доберётся проверка синтаксиса:
echo "путь: /${UNSET_VAR}/data"
# bash: UNSET_VAR: unbound variable
Но `set -e` замолкает в условиях. Вызвал функцию через
if — код возврата внутри перестал что-либо значить:
check() { false; echo "функция продолжила"; }
if check; then :; fi
# echo выполнился, rc=0
Трассировка. Обычно пишут просто
set -x, но дефолтный PS4 печатает голый плюс — в скрипте на 300 строк не поймёшь, где ты:
PS4='+ ${BASH_SOURCE}:${LINENO}: '
set -x
do_something_risky
set +x
Теперь в каждой строке трассировки видно файл и номер:
+ g.sh:4: mkdir -p /tmp/zz
Пошаговый режим. Типовой рецепт — функция с
read и ловушка DEBUG:
dbg() { read -p "$BASH_SOURCE:$LINENO? " _; }
trap 'dbg' DEBUG
В нём три поломки, и каждая тихая.
Первая:
$LINENO и $BASH_SOURCE внутри функции указывают на саму функцию. На всех командах печаталось line=3 — строка, где стоит read. Реальные 6 и 7 не появились ни разу. Координаты надо передавать аргументами:
dbg() { read -r -p "[$1:$2] $3? " _; }
trap 'dbg "$BASH_SOURCE" "$LINENO" "$BASH_COMMAND"' DEBUG
Вторая: ловушка не заходит внутрь функций. Без
set -T виден только вызов work, а команды в её теле пропадают — как раз там, где обычно и прячется баг.
set -T
Третья самая злая.
read в ловушке читает тот же stdin, что и скрипт. Подал в цикл три строки — дошла одна:
printf 'alpha\nbeta\ngamma\n' | bash f.sh
получил: beta
Две строки съела отладка — отладчик изменил поведение отлаживаемого. Плюс при неинтерактивном stdin приглашение
read -p не печатается вовсе, и скрипт молча проносится мимо пауз. Лечится перенаправлением:
dbg() { read -r -p "$1? " _ < /dev/tty; }
С ним прошли все три строки, паузы работали даже при stdin из
/dev/null.И про
bash -n, который советуют как «проверку перед запуском». Он про синтаксис и только: незакрытый if поймал с кодом 2, а несуществующую команду и rm -rf /$UNSET_VAR/data пропустил с кодом 0.Прогонял на двух машинах, bash 5.2.21 и 5.2.37 — поведение одинаковое.
А вы
set -T вообще используете или обходитесь set -x?#Linux #Bash #Debug #DevOps #Автоматизация