Что происходит
Когда вы нажимаете Ctrl+ C, SIGINT
сигнал доставляется всей группе процессов переднего плана . Здесь он отправляется как find
процессу, так и вызывающему процессу оболочки. find
реагирует, выходя немедленно, и оболочка реагирует, вызывая ловушку.
Если код в ловушке возвращается (т.е. не вызывает exit
), выполнение продолжается с командой после той, которая была прервана сигналом. Здесь после find
команды наступает конец сценария, поэтому сценарий завершается немедленно в любом случае. Но вы можете увидеть разницу между вводом 0 и 1, добавив еще одну команду:
find /
echo "find returned $?"
Способ сделать то, что вы хотите (но, вероятно, не должны делать)
Ты можешь делать, что хочешь; но эта часть моего ответа больше связана с открытием программирования оболочки, чем с решением реальной проблемы.
- С точки зрения дизайна, перезапускаемый сигнал не тот, который вы обычно ожидаете в виде относительно простых программ, которыми обычно являются сценарии оболочки. Ожидается, что Ctrl+ Cубьет скрипт.
- Как вы увидите ниже, в любом случае это немного расширяет возможности оболочки.
Если вы хотите , чтобы избежать убийства find
, вам нужно запустить его в фоновом режиме : find / &
. Затем используйте wait
встроенную функцию, чтобы дождаться нормального выхода. Сигнал будет прерывать wait
встроенную функцию, которую вы можете запустить в цикле, пока не получите сигнал, который хотите распространить. Затем используйте, kill
чтобы убить работу.
hell () {
echo "Do you want to quit? Press 1 for yes and 0 for no"
read n
if [ "$n" = 1 ]; then
# Kill the job if it's running, then exit
if [ -n "$job_pid" ]; then kill $job_pid; fi
exit 1
fi
}
job_pid=
trap "hell" SIGINT
# Start a demo job in the background
for i in 1 2 3 4 5; do date; sleep 1; done &
job_pid=$!
# Call wait in a loop; wait will return 0 if the job exits, and 128+$signum if interrupted by a signal.
while ! wait; do
echo "resuming wait"
done
job_pid=
echo last exit code: $?
Есть ограничения для этого подхода в оболочке:
- Есть условие гонки: если вы нажмете Ctrl+ Cсразу после завершения задания, но перед
job_pid=
строкой, обработчик сигнала попытается уничтожить $jobpid
, но процесс больше не существует (даже в виде зомби, потому что wait
он уже был собран), и процесс Идентификатор может быть использован другим процессом. Это не легко исправить в оболочке (возможно, установив обработчик для SIGCHLD
?).
- Если вам нужен статус возврата с работы, вам нужно использовать
wait $job_pid
форму. Но тогда вы не сможете отличить « wait
был прерван по сигналу» от «задания было убито по сигналу» (или от «задания прервано само по себе с возвращаемым статусом ≥128», но это общий факт в оболочке программирование).
- Это не будет легко распространяться, если вообще на несколько подзадач. Обратите внимание, что поведение ловушек и сигналов часто удивляет, когда вы выходите за рамки основ в большинстве реализаций оболочки (только ksh делает это хорошо).
Чтобы преодолеть эти ограничения, используйте более изящный язык, такой как Perl или Python.