Безопасное выход из цикла в bash

Скажем, у меня есть сценарий bash, который делает:

while : do foo done 

Я хотел бы иметь возможность запускать этот скрипт с консоли и иметь возможность выйти из него в произвольное время, пока это происходит между двумя прогонами foo. Поэтому, если, скажем, я нажимаю Ctrl + C (это может быть другое действие, из-за которого скрипт должен выйти, Ctrl + C – просто пример), который выйдет в следующей доступной точке после выполнения foo:

 while : do foo if [pressed_ctrl_c]: break done 

  • Сравните 2 файла с разделителями табуляции и выходных различий с заголовком столбца
  • Эпиляция языка сценариев
  • Как удалить префиксы и суффиксы из имен файлов в заданном каталоге?
  • Создание следующего доступного имени файла для шаблона (02-output.log и т. Д.)
  • Чистый способ временно заменить файл конфигурации?
  • Как добавить новую строку для отсутствующей записи между двумя полями
  • Создать мигающий текст с эхо-символами
  • Как проверить, нет ли моей переменной в наборе?
  • 2 Solutions collect form web for “Безопасное выход из цикла в bash”

    Вы можете попробовать такую ​​конструкцию:

     #!/bin/bash # INTR= trap 'INTR=yes; echo "** INTR **" >&2' INT while : do ( # Protect the subshell block trap '' INT # Protected code here echo -n "The date/time is: " sleep 2 date read -t2 -p 'Continue (y/n)? ' YN || echo test n = "$YN" && echo "Asked for BREAK" >&2 && exit 90 ) SS=$? test 90 -eq $SS && echo "Matched BREAK" >&2 && break # Ctrl/C, perhaps? test yes = "$INTR" && echo "Matched INTR" >&2 && break done exit 0 

    Некоторые примечания

    • read и test пара демонстрирует интерактивное управление защищенным сегментом кода внутри блока ( ... ) .
    • exit 90 является эквивалентом break но изнутри подоболочки. test 0 != $? ... test 0 != $? ... после того, как конец блока подоболочки будет завершен, чтобы зафиксировать статус exit 90 и реализовать break который действительно нужен коду.
    • Подоболочка может использовать разные значения статуса выхода для указания различных типов требуемого потока управления ( break , exit и т. Д.).
    • Это не мешает программе устанавливать собственный обработчик сигнала. Например, gdb устанавливает собственный обработчик для SIGINT ( Ctrl C ). Если целью является предотвращение выхода пользователя из сеанса, изменение ключа прерывания может помочь устранить ситуацию (см. Код ниже). Неэлегантный, но потенциально эффективный.

    Изменение ключа SIGINT на терминале

     G=$(stty -g) # Save settings test -n "$G" && stty intr ^A # That is caret and A, not Ctrl/A # ... SIGINT generated with Ctrl/A rather than Ctrl/C ... test -n "$G" && stty "$G" # Restore original settings 

    Это похоже на работу:

     #!/bin/sh pressed_ctrl_c= trap "pressed_ctrl_c=1" INT while true do (trap "" INT; foo)& wait || wait if [ "$pressed_ctrl_c" ] then # echo break fi done 
    • Инициализировать pressed_ctrl_c в значение null. Это, вероятно, не обязательно в скрипте.
    • trap command signum сообщает оболочке, что она настроена на фиксацию сигнального номера signum и выполняет command когда она ее ловит. «INT» сокращен для «SIGINT», который является коротким для «сигнала прерывания», который является техническим термином для сигнала, генерируемого Ctrl + C , поэтому при pressed_ctrl_c Ctrl + C оболочки pressed_ctrl_c на 1. (SIGINT имеет числовое значение 2, поэтому вы можете сказать trap "pressed_ctrl_c=1" 2 если вы хотите сэкономить при вводе текста.)
    • Внутри цикла у нас есть командная строка в круглых скобках. Это создает суб-оболочку.
    • Мы снова используем команду trap . Эта command времени является пустой строкой; это говорит оболочке игнорировать сигнальное число signum . Поскольку это находится в круглых скобках, это влияет только на подоболочку.
    • Запустить foo . Поскольку он был запущен из подоболочки, foo будет игнорировать Ctrl + C , т. Е. Он будет продолжать работать, даже если вы его foo .
    • Поместите подоболочку на задний план ….
    • … и дождитесь его завершения.
    • Если команда wait успешно, перейдите к оператору if . Если это не удается, выполните другой. (Я вернусь к этому.)
    • Если $pressed_ctrl_c установлено, вырваться из цикла. Необязательно раскомментируйте команду echo если Ctrl + C появляется на вашем терминале как ^C и вы хотите перейти к следующей строке.

    Мы запускаем команду в фоновом режиме, а затем сразу же wait ее. Это очень похоже на запуск команды на переднем плане (по крайней мере, когда это делается в скрипте). Команда wait завершится успешно, когда подоболочка завершится; т.е. когда команда foo завершается. (Команда wait будет успешно завершена, даже если foo вернет ошибку.) Когда первая команда wait завершается успешно, мы пропускаем вторую и переходим к if .

    Оболочка, которая запускает цикл, перехватывает прерывания, но подоболочка и, следовательно, процесс foo игнорируют их. Итак, когда вы pressed_ctrl_c Ctrl + C , оболочка устанавливает pressed_ctrl_c в 1 и прерывает команду (первый) wait . Поскольку первая команда wait не удалась, мы переходим ко второму. Помните, что foo по-прежнему работает, поэтому это wait все еще есть чем заняться (т. Е. Он будет ждать завершения foo ).

    Наконец, если переменная была установлена, чтобы указать, что Ctrl + C была нажата во время работы foo , отключите вывод цикла.

    Если вы дважды нажмете Ctrl + C , вторая будет прервать и прервать вторую команду wait . Это приведет к тому, что ваш скрипт завершится и вернет вас в приглашение вашей оболочки, оставив foo в фоновом режиме. Вы можете смягчить это, сказав wait || wait || wait || wait wait || wait || wait || wait wait || wait || wait || wait ; расширяя его, насколько вы хотите. Вам нужно будет набирать Ctrl + C один раз для каждого wait преждевременно завершая сценарий.

    D'о!

    Проблема в том, что процессы, которые помещаются в фоновом режиме с помощью сценария, имеют свой стандартный вход, установленный в /dev/null . Если ваш foo читается с клавиатуры, то выше будет нуждаться в пересмотре.

    Interesting Posts

    Почему графический процессор nvidia-smi редко достигает 100%?

    Сортировка слов в каждой строке, редактирование файла на месте

    Каталоги, отображаемые зеленым (исполняемым), даже после удаления разрешения на выполнение для всех

    Измените запрос Korn, чтобы показать более короткий путь для рабочего каталога

    Получение сообщений Syslog с помощью systemd Arch Linux

    Можно ли отключить Watchdog, если он включен?

    Как совместить строку с regexp и условно делать вещи с группами захвата

    Совмещение двух основных столбцов одновременно между файлами и вставка дополнительных столбцов в выходной файл, когда эти основные столбцы соответствуют

    rsync на USB-накопитель, всегда передающий все данные

    Сделать Guake Float в i3wm

    Grep для дат старше 14 дней в файле

    Как установить возможности с помощью команды setcap?

    Деактивировать новую поддержку собственных жестов в GNOME 3.14

    Минимальная среда виртуализации

    генерировать маршрутизируемый трафик для целей тестирования

    Linux и Unix - лучшая ОС в мире.