bash не завершает работу при аварийном завершении дочернего процесса из-за сигнала

bash не завершает работу при аварийном завершении дочернего процесса из-за сигнала

Я очень стараюсь понять, что я делаю не так и почему?

У меня есть launch.shскрипт, который запускает process.sh.

запуск.sh

#!/bin/bash
while true; do 
./process.sh 
done

процесс.sh

#!/bin/bash
function signalHandler() {
    for i in {1..2}; do
        sleep 0.1s
        echo "process.sh: cleanup $i"
    done
    exit 130
}

trap "signalHandler" "SIGINT"

while true; do 
sleep 1s
done

когда я бегу

./launch.sh &

а затем убить его с помощью

kill -s SIGINT -$!    

где $!берет PID последней команды (launch.sh) и минус посылает сигнал всем дочерним процессам, затем launch.shпродолжает. Почему?


Я ожидал следующего поведения (согласно этому блогу)Сигнал и Баш) :

оболочка A со скриптом, launch.shработающим в фоновом режиме, прерывается, Bash ждет process.shзавершения. Поскольку process.shпроисходит аварийный выход (выход 130) из-за обработчика сигнала в process.sh, оболочка A должна завершиться. Почему этого не происходит?

Если статус этого потомка указывает на то, что он завершился ненормально из-за этого сигнала, оболочка очищается, удаляет свой обработчик сигнала и снова завершает себя, чтобы вызвать действие ОС по умолчанию (ненормальный выход). В качестве альтернативы она запускает обработчик сигнала скрипта, установленный с помощью trap, и продолжает работу.

решение1

Во-первых, exit 130это не ненормальный выход. Это нормальный выход, со статусом выхода 130. Как видно изman 3 wait(POSIX):

   If  the  information  pointed  to  by  stat_loc was stored by a call to
   waitpid()  that  specified  the  WUNTRACED     and  WCONTINUED   flags,
   exactly one of the macros WIFEXITED(*stat_loc), WIFSIGNALED(*stat_loc),
   WIFSTOPPED(*stat_loc),  and WIFCONTINUED(*stat_loc)  shall evaluate  to
   a non-zero value.

WIFEXITEDпроверяет нормальный выход, и WIFSIGNALLEDявляется завершением из-за неперехваченного сигнала. Поскольку они являются взаимоисключающими, exit 130является нормальным.

Тот факт, что при завершении процесса по сигналу SIGINT код выхода равен 130, объясняется тем, что bash устанавливает его равным 130 за пределами процесса, поскольку он обнаружил выход по сигналу SIGINT:Почему bash устанавливает $? (статус выхода) в ненулевое значение при нажатии Ctrl-C или Ctrl-Z?

Во-вторых, процесс, который обрабатывает SIGINT и затем умирает, должен убить себя с помощью SIGINT. Вики Грега (отличный ресурс для shell-материалов) естьзаметка по этому поводу:

Если вы решили настроить обработчик для SIGINT (вместо использования ловушки EXIT), вы должны знать, что процесс, который завершается в ответ на SIGINT, долженубить себя с помощью SIGINTа не просто выйти, чтобы не создавать проблем для вызывающего. Таким образом:

trap 'rm -f "$tempfile"; trap - INT; kill -INT $$' INT

Теперь, если вы изменили exit 130на:

trap - INT
kill -INT $$

Вы увидите ожидаемое поведение.

Связанный контент