Почему фоновая задача bash игнорирует SIGINT?

Я заметил, что sleep нельзя убить с помощью SIGINT, когда он порождается:

(sleep 1000 &)

Интересно, почему так.
SIGINT убивает все перечисленное ниже:

sleep 1000
sleep 1000 &
(sleep 1000)
( ( (sleep 1000) ) )
( ( (sleep 1000)& ) )

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

Я написал короткую программу на C для проверки поведения и обнаружил, что sa_handler имеет значение SIG_IGN, что объясняет явление, но почему именно так?

Я не нашел никакой информации, является ли эта функция задуманной (хотя, учитывая длину руководства, я мог просто пропустить ее), и если да, то по какой причине она была скрыта.

Я включаю код C для тех, кто заинтересован:

#include <stdlib.h>
#include <stdio.h>

#include <signal.h>

int main() {
    struct sigaction oldact;
    if(sigaction(SIGINT, NULL, &oldact) != 0) {
        printf("Error in sigaction\n");
        exit(1);
    }

    if(oldact.sa_flags & SA_SIGINFO) {
        printf("Using sa_sigaction\n");
    } else {
        if(oldact.sa_handler == SIG_DFL) {
            printf("Default action\n");
        } else if(oldact.sa_handler == SIG_IGN) {
            printf("Ignore signal\n");
        } else {
            printf("Other action\n");
        }
    }
    return 0;
}

РЕДАКТИРОВАТЬ:

ответ на подсказку великолепен, и я принял его. Я хотел добавить относительно почему posix говорит, что согласно signal(7) и SIGINT, и SIGQUIT с клавиатуры. Так что имеет смысл игнорировать их в процессах, отсоединенных от одного (а не в задачах, контролируемых bash).

EDIT2:

Checkout Отметить комментарий Плотника для истинного объяснения ПОЧЕМУ.


person yjay    schedule 10.03.2020    source источник


Ответы (1)


Эта конструкция (sleep 1000 &) помещает вашу команду sleep во внучатую подоболочку без управления заданиями:

your-shell
      \
      a compound-list in a subshell
          \
         an asynchronous list in a subshell

Первая подоболочка, ( составной список ) (a конструкция команды grouping), просто запускает фоновую команду & (асинхронный список), а затем завершает работу. Асинхронный список запускается в собственной подоболочке.

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

Согласно POSIX, "[i]если управление заданиями отключено... когда оболочка выполняет асинхронный список, команды в списке должны наследовать от оболочки действие сигнала игнорируемого (SIG_IGN) для сигналов SIGINT и SIGQUIT."

Таким образом, ваш sleep запускается с игнорированием SIGINT.

person pilcrow    schedule 11.03.2020
comment
Я не понимаю, зачем добавлять такой хитрый случай. Есть ли причина этого наследства? Поскольку о контроле над заданиями не может быть и речи, зачем вообще менять поведение процесса по умолчанию? - person yjay; 11.03.2020
comment
@yjay Если управление заданиями отключено, оболочка не будет создавать новую группу процессов для каждой команды. Если вы запустите асинхронную команду (&) и наберете в оболочке control-C, и оболочка, и асинхронная команда получат сигнал SIGINT. Обычно это завершает асинхронный процесс, поэтому оболочка делает разумную вещь и заставляет такие процессы игнорировать SIGINT и SIGQUIT. - person Mark Plotnick; 11.03.2020