Как заставить Ctrl + C / Not / прерывать цикл while?

11

Учитывая этот цикл:

while sleep 10s ; do
  something-that-runs-forever
done

Когда я нажимаю Ctrl + C, весь цикл while прерывается. Я хочу прервать процесс «что-то», пропустить 10 секунд, а затем перезапустить «что-то».

Как сделать так, чтобы Ctrl + C влиял только на «что-то», а не на цикл while?

РЕДАКТИРОВАТЬ: «прерывать», как в SIGINT. Убийство. Прервать. Прервать. Не «прерывать», как в «паузе».

BOS
источник
Если вы просто хотите приостановить его, почему бы не использовать Ctrl + Z, подождать 10 секунд и запустить fg? Зачем вообще использовать Ctrl + C?
Terdon
@terdon: Спасибо за комментарий, может быть, я поспешил с ответом. Нужно читать больше о требовании ОП
Инян
@terdon: Я не хочу останавливать это. Я хочу, чтобы прошло 10 секунд, как я написал.
Бос
Вы сказали: What I want to do is to interrupt the "something"-process, let 10 seconds pass, and then restart "something". Если вы нажмете Ctrl + Z, подождите 10 секунд и затем запустите fg, это именно то, что произойдет. Может быть, вы могли бы отредактировать свой вопрос и привести конкретный пример, чтобы мы могли лучше понять?
Terdon
3
Я думал, что в контексте Ctrl + C прерывание было однозначным, но, очевидно, я ошибался. Я сейчас отредактировал.
Бос

Ответы:

18

Это должно работать, если вы просто trap SIGINTк чему-то. Нравится :( true).

#!/bin/sh
trap ":" INT    
while sleep 10s ; do
    something-that-runs-forever
done

Прерывание something...не заставляет оболочку выходить сейчас, поскольку она игнорирует сигнал. Однако, если вы запустите sleepпроцесс, он завершится с ошибкой, и цикл остановится из-за этого. Переместите sleepвнутрь цикла или добавьте что-то подобное, || trueчтобы предотвратить это.

Обратите внимание, что если вы используете trap "" INTдля полного игнорирования сигнала (вместо назначения ему команды), он также игнорируется в дочернем процессе, поэтому вы также не можете прерывать его something.... Это явно упоминается по крайней мере в руководстве Bash :

Если arg является пустой строкой, то сигнал, указанный каждым sigspec , игнорируется оболочкой и командами, которые он вызывает. [...] Сигналы, игнорируемые при входе в оболочку, не могут быть перехвачены или сброшены.

ilkkachu
источник
Может ли это быть достигнуто и в текущей оболочке? (Не в сценарии.)
1
Вы можете do (trap - INT; something-that-runs-forever)разрешить прерывание команды. Кроме того , вам не нужно бежать :- вы можете просто использовать пустую строку , чтобы игнорировать сигнал: trap '' INT. Все это POSIX и должно работать на любой совместимой оболочке (не только на Bash).
Тоби Спейт
Также обратите внимание, что запись SIGINTв полном объеме не является строго переносимой: « Реализации могут разрешать имена с SIGпрефиксом или игнорировать регистр в именах сигналов как расширение . » (Мой акцент)
Тоби Спейт,
Вы можете передать пустую строку как действие, чтобы игнорировать сигнал, например trap "" INT(также posix)
daf
@TobySpeight, причина, которую я использовал trap :вместо этого, trap ""заключалась именно в том, чтобы не игнорировать сигнал (но вместо этого сделать его бездействующим ), так что нам не нужно ничего делать, чтобы иметь возможность прерывать основную somethingпрограмму.
ilkkachu
0

Другой вариант - заставить something-that-runs-foreverобрабатывать сигнал (грациозно выходить при его получении). Конечно, это имеет смысл делать только тогда, когда эта программа используется во многих сценариях, а желаемое поведение на CTRL+ Cсистематически одинаково - продолжать выполнение сценария.

Дмитрий Григорьев
источник
ITYM "спать и самовоспроизводиться", а не "выйти изящно"?
Тоби Спейт