Контроль, который отменяется с помощью Ctrl + C

У меня есть живой CD, который загружается в Linux и запускает небольшой скрипт Bash. Сценарий ищет и запускает вторую программу (обычно это скомпилированный двоичный файл C ++).

Предполагается, что вы можете прервать вторую программу, нажав Ctrl + C. Что должно произойти, так это то, что вторая программа останавливается, а сценарий Bash продолжает выполнять очистку. На самом деле происходит то, что и основное приложение, и сценарий Bash завершаются. Это проблема.

Поэтому я использовал встроенную trap чтобы сообщить Bash игнорировать SIGINT. И теперь Ctrl + C завершает приложение C ++, но Bash продолжает свой запуск. Отлично.

О да … Иногда «второе приложение» – это еще один сценарий Bash. И в этом случае Ctrl + C теперь ничего не делает.

Ясно, что мое понимание того, как работает этот материал, неверно … Как я могу контролировать, какой процесс получает SIGINT, когда пользователь нажимает Ctrl + C? Я хочу направить этот сигнал только на один конкретный процесс .

3 Solutions collect form web for “Контроль, который отменяется с помощью Ctrl + C”

После многих, многих часов поиска в Интернете, я нашел ответ.

  1. Linux имеет понятие группы процессов .

  2. Драйвер TTY имеет понятие о Foreground Process Group.

  3. Когда вы нажимаете Ctrl + C, TTY отправляет SIGINT для каждого процесса в группе Foreground Process Group. (См. Также эту запись в блоге .)

Вот почему и скомпилированный двоичный файл, и скрипт, который запускает его, также сбиваются. На самом деле, я хочу, чтобы основное приложение получало этот сигнал, а не сценарии запуска.

Решение теперь очевидно: нам нужно поставить приложение в новую группу процессов и сделать его группой Foreground Process для этого TTY. По-видимому, команда для этого

 setsid -c <applcation> 

И это все. Теперь, когда пользователь нажимает Ctrl + C, SIGINT будет отправлен в приложение (и любые его дочерние элементы), и никто другой. Это то, что я хотел.

  • setsid сам по себе ставит приложение в новую группу процессов (действительно, совершенно новую «сессию», которая, по-видимому, является группой групп процессов).

  • Добавление флага -c заставляет эту новую группу процессов стать группой процессов «переднего плана» для текущего TTY. (Т.е., он получает SIGINT, когда вы нажимаете Ctrl + C.)

Я видел много противоречивой информации о том, когда Bash выполняет или не запускает процессы в новой группе процессов. (В частности, он кажется другим для «интерактивных» и «неинтерактивных» оболочек.) Я видел предложения о том, что вы можете заставить это работать с умной трюкой трубы … Я не знаю. Но этот подход, похоже, работает для меня.

В исходном скрипте bash.

  • отслеживать ПИД второй программы

  • поймать SIGINT

  • когда вы поймали SIGINT, отправьте SIGINT во вторую программу PID

Как я упоминал в комментарии к f01, вы должны отправлять SIGTERM в дочерний процесс. Вот несколько сценариев, которые показывают, как захватить ^ C и отправить сигнал дочернему процессу.

Во-первых, родитель.

TRAPtest

 #!/bin/bash # trap test # Written by PM 2Ring 2014.10.23 myname=$(basename "$0") child=sleeploop set_trap() { sig=$1 msg="echo -e \"\n$myname received ^C, sending $sig to $child, $pid\"" trap "$msg; kill -s $sig $pid" SIGINT } trap "echo \"bye from $myname\"" EXIT echo "running $child..." ./$child 5 & pid=$! # set_trap SIGINT set_trap SIGTERM echo "$child pid = $pid" wait $pid echo "$myname finished waiting" 

А теперь, ребенок.

sleeploop

 #!/bin/bash # child script for traptest # Written by PM 2Ring 2014.10.23 myname=$(basename "$0") delay="$1" set_trap() { sig=$1 trap "echo -e '\n$myname received $sig signal';exit 0" $sig } trap "echo \"bye from $myname\"" EXIT set_trap SIGTERM set_trap SIGINT #Select sleep mode if false then echo "Using foreground sleep" Sleep() { sleep $delay } else echo "Using background sleep" Sleep() { sleep "$delay" & wait $! } fi #Time to snooze :) for ((i=0; i<5; i++)); do echo "$i: sleeping for $delay" Sleep done echo "$myname terminated normally" 

Если traptest отправляет SIGTERM, то поведение ведет себя красиво, но если traptest отправляет SIGINT, то Sleploop его никогда не увидит.

Если ловушки спящего режима SIGTERM и режим сна являются передними, то он не может реагировать на сигнал, пока он не просыпается от текущего сна. Но если спящий режим – фон, он немедленно ответит.

  • Отправлять конкретный номер сигнала с помощью определенного ключа
  • Есть ли способ выйти из режима «меньше», не останавливая другие процессы в трубе?
  • Сценарий Bash не видит SIGHUP?
  • Как заставить «xargs» игнорировать выход ребенка и продолжить обработку
  • Как перезапустить (или сбросить) запущенный процесс в Linux
  • В отсутствие обработчика сигналов SIGTERM ведет себя одинаково с SIGKILL?
  • Код сбоя и выхода 721035
  • Элементы управления TTY, отправленные в stdin sh, не работают
  • Что делает этот logrotate config nginx?
  • разница между signalfd и sigwaitinfo?
  • В какой документации показаны связанные номера для сигналов Linux, таких как SIGTERM и SIGKILL?
  • Linux и Unix - лучшая ОС в мире.