TGViewer
LinuxSkill - Сводки с прода и Шпаргалки LinuxSkill - Сводки с прода и Шпаргалки @linuxskill · 10.7K subscribers
Post #1212 1.76K
Ходовой набор для отладки bash-скрипта известен всем: 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 #Автоматизация
  • 👀 2
  • 👍 1
More from @linuxskill
  1. Oct 2, 2026📊 Диск тормозит, а iostat показывает норму? Ищем хвост задержек Приложение подвисает на з…
  2. Sep 30, 2026💀 CPU под 100%, а в top пусто? Ловим невидимые процессы через eBPF Сервер греется, в шапк…
  3. Sep 28, 2026🔥 Знаешь только ip a? 10 неочевидных команд ip для Linux Большинство админов знают про ip…
  4. Sep 25, 2026Разобрать строку штатным <regex.h> и не получить молчаливое «нет совпадения». Проверял на…
  5. Sep 23, 2026Закрыть периметр правилами iptables и не остаться при этом за дверью вместе с атакующим. П…
  6. Sep 21, 2026Добавить пользователя в группу и не выкинуть его при этом из sudo Добавить во вторичную гр…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →