Учебники

Unix / Linux — сигналы и ловушки

В этой главе мы подробно обсудим сигналы и ловушки в Unix.

Сигналы — это программные прерывания, посылаемые программе, чтобы указать, что произошло важное событие. События могут варьироваться от пользовательских запросов до недопустимых ошибок доступа к памяти. Некоторые сигналы, такие как сигнал прерывания, указывают, что пользователь попросил программу сделать что-то, что не соответствует обычному потоку управления.

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

Название сигнала Номер сигнала Описание
SIGHUP 1 Обнаружено зависание на управляющем терминале или смерть контролирующего процесса
SIGINT 2 Выдается, если пользователь отправляет сигнал прерывания (Ctrl + C)
SIGQUIT 3 Выдается, если пользователь отправляет сигнал выхода (Ctrl + D)
SIGFPE 8 Выдается при попытке выполнить недопустимую математическую операцию
SIGKILL 9 Если процесс получает этот сигнал, он должен немедленно завершить работу и не будет выполнять никаких операций очистки.
SIGALRM 14 Сигнал будильника (используется для таймеров)
SIGTERM 15 Сигнал завершения работы программы (по умолчанию отправляется kill)

Список сигналов

Существует простой способ составить список всех сигналов, поддерживаемых вашей системой. Просто введите команду kill -l, и она отобразит все поддерживаемые сигналы —

$ kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL
 5) SIGTRAP      6) SIGABRT      7) SIGBUS       8) SIGFPE
 9) SIGKILL     10) SIGUSR1     11) SIGSEGV     12) SIGUSR2
13) SIGPIPE     14) SIGALRM     15) SIGTERM     16) SIGSTKFLT
17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU
25) SIGXFSZ     26) SIGVTALRM   27) SIGPROF     28) SIGWINCH
29) SIGIO       30) SIGPWR      31) SIGSYS      34) SIGRTMIN
35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3  38) SIGRTMIN+4
39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12
47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14
51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10
55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7  58) SIGRTMAX-6
59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

Фактический список сигналов варьируется между Solaris, HP-UX и Linux.

Действия по умолчанию

С каждым сигналом связано действие по умолчанию. Действие по умолчанию для сигнала — это действие, которое скрипт или программа выполняет при получении сигнала.

Некоторые из возможных действий по умолчанию —

  • Завершить процесс.

  • Игнорировать сигнал.

  • Дамп ядро. Это создает файл с именем core, содержащий образ памяти процесса, когда он получил сигнал.

  • Останови процесс.

  • Продолжить остановленный процесс.

Завершить процесс.

Игнорировать сигнал.

Дамп ядро. Это создает файл с именем core, содержащий образ памяти процесса, когда он получил сигнал.

Останови процесс.

Продолжить остановленный процесс.

Отправка сигналов

Существует несколько способов доставки сигналов в программу или скрипт. Одним из наиболее распространенных для пользователя является ввод CONTROL-C или клавиши INTERRUPT во время выполнения скрипта.

Когда вы нажимаете клавишу Ctrl + C , SIGINT отправляется в сценарий и в соответствии с определенным сценарием действия по умолчанию завершается.

Другим распространенным методом доставки сигналов является использование команды kill , синтаксис которой следующий:

$ kill -signal pid

Здесь сигнал — это либо номер, либо имя сигнала для доставки, а pid — идентификатор процесса, на который должен быть отправлен сигнал. Например —

$ kill -1 1001

Приведенная выше команда отправляет HUP или сигнал зависания программе, которая выполняется с идентификатором процесса 1001 . Чтобы отправить сигнал уничтожения тому же процессу, используйте следующую команду —

$ kill -9 1001

Это убивает процесс, запущенный с идентификатором процесса 1001 .

Сигналы захвата

Когда вы нажимаете клавиши Ctrl + C или Break на вашем терминале во время выполнения программы оболочки, обычно эта программа немедленно завершается, и ваша командная строка возвращается. Это не всегда может быть желательным. Например, вы можете оставить кучу временных файлов, которые не будут очищены.

Перехват этих сигналов довольно прост, и команда trap имеет следующий синтаксис:

$ trap commands signals

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

Существует два распространенных варианта использования ловушек в сценариях оболочки:

  • Очистить временные файлы
  • Игнорировать сигналы

Очистка временных файлов

В качестве примера команды trap, ниже показано, как вы можете удалить некоторые файлы и затем выйти, если кто-то попытается прервать программу из терминала —

$ trap "rm -f $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 2

С того момента, как в программе оболочки будет выполнена эта ловушка, два файла work1 $$ и dataout $$ будут автоматически удалены, если программа получит сигнал № 2.

Следовательно, если пользователь прерывает выполнение программы после выполнения этой ловушки, вы можете быть уверены, что эти два файла будут очищены. Команда выхода, которая следует за rm , необходима, потому что без нее выполнение программы продолжится в той точке, в которой она остановилась, когда был получен сигнал.

Сигнал № 1 генерируется для зависания . Либо кто-то намеренно вешает трубку, либо она случайно отключается.

Вы можете изменить предыдущую ловушку, чтобы также удалить два указанных файла в этом случае, добавив сигнал номер 1 в список сигналов —

$ trap "rm $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 1 2

Теперь эти файлы будут удалены, если строка зависнет или будет нажата клавиша Ctrl + C.

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

Таким образом, в предыдущем примере значения WORKDIR и $$ будут подставлены во время выполнения команды trap. Если вы хотите, чтобы эта замена произошла во время получения сигнала 1 или 2, вы можете поместить команды в одинарные кавычки —

$ trap 'rm $WORKDIR/work1$$ $WORKDIR/dataout$$; exit' 1 2

Игнорирование сигналов

Если команда, указанная для trap, является нулевой, указанный сигнал будет игнорироваться при получении. Например, команда —

$ trap '' 2

Это указывает на то, что сигнал прерывания должен игнорироваться. Возможно, вы захотите игнорировать определенные сигналы при выполнении операции, которую вы не хотите прерывать. Вы можете указать несколько сигналов, которые будут игнорироваться, следующим образом:

$ trap '' 1 2 3 15

Обратите внимание, что первый аргумент должен быть указан для сигнала, который следует игнорировать, и он не эквивалентен записи следующего, который имеет отдельное значение —

$ trap  2

Если вы игнорируете сигнал, все подоболочки также игнорируют этот сигнал. Однако, если вы укажете действие, которое будет выполняться при получении сигнала, все подоболочки все равно будут выполнять действие по умолчанию при получении этого сигнала.

Сброс ловушек

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

$ trap 1 2

Это сбрасывает действие, которое необходимо выполнить при получении сигналов 1 или 2, до значения по умолчанию.