Pull to refresh

Comments 37

Отличная идея! Можно ещё позволить выполнять команды перед каждой строкой:

function _debug_for_bash() {
    echo "# $BASH_COMMAND";
    while read -p "debug> " _cmnd; do
        if [ -n "$_cmnd" ]; then
            eval "$_cmnd";
        else
            break;
        fi;
    done
}

trap '_debug_for_bash' DEBUG

А ещё можно сделать скрипт, который будет всё это делать для другого скрипта.

Пожалуй причешу и утащу в блог, с указанием авторства оригинала, разумеется.

Более того, в рамках этого решения еще и breakpoint-ы можно реализовать.

У меня всё и началось именно с них - я использовал read в этом качестве, добавляя его везде, где хотелось, чтоб была точка останова. Эдакий аналог Octave-ского keyboard.

Добавлять read для останова не очень удобно. Я имел в виду, что при вызове _debug_for_bash можно проверять номер строки на которой сработал trap. И запускать цикл с read только если этот номер находится в списке breakpoint-ов. В цикле перед eval надо добавить обработку команд на добавление и удаление breakpoint-ов.

Ну вот это может оказаться очень тяжеловесно... Если @selivanov_pavel сделает в виде отдельного скрипта, тогда и хорошо. А если таскать из скрипта в скрипт много строк кода, тогда, возможно, и не стоит.. впрочем, тут дело вкуса и того, как оно будет реализовано. Не готов заранее оценивать юзабельность этого.

Вот спасибо хорошо! Я пытался подобное сделать, но моего баш кунг фу в сочетании с тем, что было достаточно приведённого решения, не хватило для того, чтоб закончить.

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

Добавил расцветки и вместо строки «debug>» занес в приглашение код ошибки:
while read -r -e -p "$(echo -e "\e[0;31m${_bash_debug_last_retcode//0/$(echo -e "\e[0;32m#\e[0m")}\e[0m \e[1m$BASH_COMMAND\e[0m") " _bash_debug_command; do
        if [ -n "$_bash_debug_command" ]; then
            eval "$_bash_debug_command";
        else
            break;
        fi;
    done
так и сделал — вывожу зеленым "#", если код ошибки «0». А если не ноль, то красным цифру.
А жирным-ярким команду, а вывод команды менее ярким

А можно просто отлаживать скрипты включив режим отладки bash

set -x

Или можно совместить с холостым выполнением bash

set -n

Я искренне думал, что эта статья сведётся к строчке

set -euxo pipefail

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

Про опцию -n я не слышал. Спасибо, попробую.

Всё ниже указанное стоит рассматривать как мой личный опыт, и моё мнение может не совпадать с мнением коллег, потому не стоит воспринимать как истину последней инстанции.

С bash я работаю плотно с 2009 года. За это время я имел опыт работы с perl, python, awk, sed, jq, bc, dc, grep и прочими типичными инструментами связанными с работой в эмуляторах терминала. На протяжении этого периода стиль моего написания скриптов менялся несколько раз. На данный момент те задачи, которые я решаю с помощью bash, не требуют контроля пошагового выполнения, и этому есть три причины.

Во-первых, из всех написанных мною скриптов, используемые по сей день скрипты отличаются прямолинейностью алгоритма. По мере получения опыта я стараюсь сводить к минимуму использования условных операторов, циклов и других элементов контроля выполнения. Например, по циклам предел вложенности в моих скриптах очень редко достигает трёх циклов, обычно не больше двух. Если задача требует более сложных структур, я разделяю её на несколько маленьких скриптиков. Я предпочитаю именно несколько скриптиков в отдельных файлах вместо использования функций в одном файле. Если задача требует алгоритмов из алгоритмизации или, не дай бог, вычислительной математики. Например, для поиска всех пересечений двух кубических кривых безье, вместо bash я отдал бы предпочтение чему-либо другому. И даже дело не в том, что bash скуден на инструментарий решения математики. Объединяя средства bash, perl, awk, grep мощность обработки строк и манипуляций с текстовыми или полу-текстовыми потоками с лихвой компенсирует слабую математическую сторону bash. Простые скрипты с линейным алгоритмом на bash хочется использовать снова и снова. А когда в скрипте десятки точек выхода, рекурсивных вызовов, бесконечных циклов, такие скрипты пишутся на один раз. А потом, открыв такой скрипт даже вспоминать не хочется, что сам там накодил.

Во-вторых, не смотря на линейность алгоритма, скрипты могут быть большими, и их может быть много. Например, рабочая сборка livecd содержит более 250 пакетов из AUR. Это же сколько тысяч раз мне надо нажать на Enter, пока сформируется репозиторий с актуальными версиями рабочего софта!

В-третьих, если запустить bash без параметров, он как раз откроется в похожем режиме. Бонусом этого режима является возможность контролировать ход выполнения скрипта, задавая новые значения переменным и редактируя команды скрипта. Побочным эффектом такого подхода будет необходимость искусно манипулировать историей команд и реверсивным поиском. Ну, или копировать-вставлять в окно эмулятора терминала по-командно. Тоже опыт. Кстати, именно в таком режиме я веду разработку особо длинных команд bash.

Завершить свой монолог хочу действительно правильным советом и напутствием. Пишите скрипты на bash только для собственного использования на подконтрольных вам компьютерах и серверах. А когда будете писать скрипты с расчетом того, что их будут запускать другие люди на других разных компьютерах, такие скрипты пишите на sh. Да, там нет того синтаксического сахара bash. Скрипты на sh пишутся чуть дольше и чуть длиннее. Но это время окупится. Не сомневайтесь! Коллеги в чужих скриптах разбираться не любят. Скинут вывод ошибки, которую вы часами будете пытаться воспроизвести. А в итоге выяснится, что запускают скрипт на каком-нибудь osx или каким-нибудь древним busybox. Рано или поздно все приходят к sh. Back to the primitive (c)Soulfly. А для своих нужд я лично уже наверное года 4 пользуюсь fish. Пробовал zsh - мне лично не зашёл. У fish лучший autocomplete по клавише Tab прямо из коробки. Но скрипты все равно пишу на bash/sh.

Также ещё хочется дать напутствие. Попробуйте разобраться как работает readline. Вы им пользуетесь каждый рабочий день, но никогда не задумывались о нём. Этот чёрный ящик линукса вообще мало кто любит трогать. В коде так почти ничего не поменяли с 90х годов. Попробуйте, например, поменять сигналы на другие комбинации клавиш, а Ctrl+x забиндить вырезать, Ctrl+c - скопировать, Ctrl+v - вставить, Ctrl+z - отменить, Ctrl+a - выделить всё. К тому моменту когда у вас получится это сделать, вы будете гораздо больше понимать в терминалах и, собственно, почему их эмулируют. Эх, может через пару-тройку лет настанет день, и я напишу огромнейший пост про readline.

Было бы круто! Про readline я пытался начинать читать, но как-то, видимо, не в то время.

По поводу линейности скриптов - полностью поддерживаю. Лично я отлаживал сценарии плдготовки релиза - скрипт, который на ветках запускает тесты, мержит с веток в мастер, запускает тесты на мастере и добавляет метку релиза, но не пушит, пушу я руками, если всё ок.

Т.е. скрипт прямолинейный и простой. И пользуюсь им только я.

Недавно мне надо было написать скрипт для docker alpine и я так и не смог нагуглить какой-нибудь нормальный cheat sheet для sh, так как в выдаче поиска был один только bash. Пришлось добавить apk add --no-cache bash.

Кто-нибудь может поделиться ссылкой на удобный справочник по sh?

Каждый сам - кузнечик своего счастья. Возьмите, сделайте одну удобную книжку, люди вам спасибо скажут.

А ваш чит шит - это… ну, такое себе. Про перенаправление поговорили, а такой постоянно используемый конструкт, как `2>&1` забыли. `sort | uniq ` - это смешно. Разве `sort -u` не короче? Про то, что '[' - это отдельная программа (утилита) - не сказали. Как и про то, что можно писать (например) `if kill -0 $$; then echo "I'm alive, alive!"; fi`. Про `&&`/`||` сказали, а про то, что там есть маааленькая такая особенность их взаимодействия - не упомянули.

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

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

А когда будете писать скрипты с расчетом того, что их будут запускать
другие люди на других разных компьютерах, такие скрипты пишите на sh.

Только не sh, а dash. sh - это символическая ссылка на bash или dash (в зависимости от системы).

Более того, если bash определяет, что он запущен как sh, он выполняется в особом режиме POSIX-совместимости, хотя при этом и продолжает быть bash.

Без настроенного PS4 этого мало для эффективной отладки

С bashdb надо заморачиваться, нет его в "базовой комплектации". А работать иногда приходится на серверах, где у меня нет админских прав.

Ну, права на $HOME есть же? Закинуть заранее собранный bashdb .

Хотя, если bashdb действительно необходим - значит что то делается совсем неправильно. :)

Если ваш скрипт надо отлаживать, то его стоило бы написать на нормальном языке

есть bash script debug extension для VSCode и там реализованы все нужные вещи - step over, step in, breakpoints и т.п.:

https://marketplace.visualstudio.com/items?itemName=rogalmic.bash-debug

еще есть в природе bash debug project для любителей консоли:

http://bashdb.sourceforge.net/

имея эти две вещи можно забыть про извращения вида "как еще сделать отладочный вывод (prinf после каждой строчки) более похожим на нормальную отладку" описанные в статье :)

Про плагин для vscode не знал. В хорошее время мы живём... ничего делать не надо - надо просто найти то, что уже кем-то сделано до нас.

Использование плагина vscode ограничивает выбор окружения, отладить скрипт на сервере уже не получится.

Отлаживать неотлаженные скрипты на проде - не лучшая затея.

Удалённый тестовый сервер. Или удалённая one-shot disposable machine для проверки теории. Часто приходится работать с таким

В тестовый сервер можно и отладчик установить, и vscode со всеми плагинами.

Это да, но если сервер боевой - как-то не по себе копировать туда непонятно откуда взявшийся nodejs с килограммом js-кода из дополнений с сомнительной степенью безопасности. VSCode именно так работает через ssh сессию, там не просто sshfs.

Sign up to leave a comment.

Articles