sleep, espera e propagação Ctrl + C

3

Se eu tiver o seguinte script de shell

sleep 30s

E apertei Ctrl + C quando o script de shell está rodando, o sleep morre com ele.

Se eu tiver o seguinte script de shell

sleep 30s &
wait

E apertei Ctrl + C quando o script de shell está rodando, o sleep continua, e agora tem um pai de 1.

Por que isso? Não propagou Ctrl + C para todos os filhos?

EDITAR: Se eu tiver o seguinte script

/usr/bin/Xvfb :18.0 -ac -screen 0 1180x980x24 &
wait

onde estou gerando um programa, desta vez Ctrl + C no processo principal mata o processo Xvfb também.

Então, como e por que Xvfb é diferente do sono?

No caso de alguns processos, vejo que eles são coletados por init , em alguns casos eles morrem. Por que o sono é obtido pelo init? Por que Xvfb morre?

    
por Hari Sundararajan 30.10.2018 / 02:23

3 respostas

6

tl; dr; o processo Xvfb define um manipulador de sinal para SIGINT e sai quando recebe tal sinal, mas o processo sleep não, então ele herda o "ignore" o estado para SIGINT como foi definido pelo shell executando o script antes de executar o sleep binário.

Quando um script de shell é executado, o controle de trabalho é desativado e os processos em segundo plano (aqueles iniciados com & ) são executados no mesmo grupo de processos, com SIGINT e SIGQUIT definido como SIG_IGN (ignorado) e com seu stdin redirecionado de /dev/null .

Isso é exigido pelo padrão :

If job control is disabled (see the description of set -m) when the shell executes an asynchronous list, the commands in the list shall inherit from the shell a signal action of ignored (SIG_IGN) for the SIGINT and SIGQUIT signals.

Se a disposição do sinal estiver definida como SIG_IGN (ignorar), esse estado será herdado por meio de fork() e execve() :

Signals set to the default action (SIG_DFL) in the calling process image shall be set to the default action in the new process image. Except for SIGCHLD, signals set to be ignored (SIG_IGN) by the calling process image shall be set to be ignored by the new process image.

    
por 30.10.2018 / 17:31
2

Na página de manual do bash :

Background processes are those whose process group ID differs from the terminal’s; such processes are immune to keyboard-generated signals

Você poderia lidar com isso de maneiras diferentes; primeiro, para matar os trabalhos listados:

#!/bin/bash
trap 'kill $(jobs -p)' INT
sleep 30s &
wait

Como alternativa, envie um kill para todos os processos no mesmo grupo de processos:

#!/bin/bash
trap 'kill 0' INT
sleep 30s &
wait
    
por 30.10.2018 / 02:56
0

O Bash não encaminha sinais como SIGINT ou SIGTERM para processos nos quais está atualmente aguardando.

Uma solução comum é fazer um trap wait wait, conforme mostrado no exemplo a seguir:

int_handler()
{
    kill -TERM "${child_pid}" > /dev/null 2>&1
}

trap 'int_handler' INT

echo "Sleeping ... "
sleep 200 &

child_pid=$!
wait ${child_pid} > /dev/null 2>&1
trap - INT
wait ${child_pid} > /dev/null 2>&1
    
por 30.10.2018 / 04:04

Tags