2013-02-04 2 views
7

Gibt es eine Möglichkeit, einen Unterprozess aufzurufen, so dass es und alle seine Nachkommen einen Interrupt gesendet werden, so als ob Sie eine Vordergrundaufgabe Strg-C? Ich versuche, ein Startprogramm zu beenden, das ein lang laufendes Kind aufruft. Ich habe versucht, kill -SIGINT $child (die den Interrupt nicht an seine Nachkommen sendet so ist ein No-Op) und kill -SIGINT -$child (die funktioniert, wenn interaktiv aufgerufen, aber nicht bei der Ausführung in einem Skript).Wie kann bash script das Äquivalent von Ctrl-C zu einer Hintergrundaufgabe machen?

Hier ist ein Testskript. Das Skript mit langer Laufzeit ist test.sh --child. Wenn Sie test.sh --parent aufrufen, ruft es test.sh --child & auf und versucht dann, es zu beenden. Wie kann ich den Eltern das Kind erfolgreich töten lassen?

#!/bin/bash 

if [ "$1" = "--child" ]; then 
sleep 1000 

elif [ "$1" = "--parent" ]; then 
"$0" --child & 
for child in $(jobs -p); do 
    echo kill -SIGINT "-$child" && kill -SIGINT "-$child" 
done 
wait $(jobs -p) 

else 
echo "Must be invoked with --child or --parent." 
fi 

Ich weiß, dass Sie das lang laufende Kind trap Signale modifizieren, um sie zu seinen subprocess senden, und warten Sie dann (von Bash script kill background (grand)children on Ctrl+C), aber ist es eine Möglichkeit, das Kind Skript ohne Änderung?

Antwort

4

dies lesen: How to send a signal SIGINT from script to script ? BASH

Auch von info bash

To facilitate the implementation of the user interface to job control, 
    the operating system maintains the notion of a current terminal process 
    group ID. Members of this process group (processes whose process group 
    ID is equal to the current terminal process group ID) receive keyboard- 
    generated signals such as SIGINT. These processes are said to be in 
    the foreground. Background processes are those whose process group ID 
    differs from the terminal's; such processes are immune to keyboard-gen‐ 
    erated signals. 

So bash unterscheidet Hintergrundprozesse von Vordergrundprozesse durch die Prozessgruppen-ID. Wenn die Prozessgruppen-ID gleich Prozess-ID ist, dann ist der Prozess ein Vordergrundprozess und wird beendet, wenn er ein.-Signal empfängt. Andernfalls wird es nicht beendet (es sei denn, es ist gefangen).

Sie können die Prozessgruppe Id mit

ps x -o "%p %r %y %x %c " 

So sehen, wenn Sie einen Hintergrundprozess (mit &) aus einem Skript ausführen, wird es das SIGINT Signal ignorieren, es sei denn, es gefangen ist.

Sie können jedoch den untergeordneten Prozess mit anderen Signalen wie SIGKILL, SIGTERM usw. weiterhin beenden.

Zum Beispiel, wenn Sie Ihr Skript das es folgende ändern wird erfolgreich das Kind Prozess töten:

#!/bin/bash 

if [ "$1" = "--child" ]; then 
    sleep 1000 
elif [ "$1" = "--parent" ]; then 
    "$0" --child & 
    for child in $(jobs -p); do 
    echo kill "$child" && kill "$child" 
    done 
    wait $(jobs -p) 

    else 
    echo "Must be invoked with --child or --parent." 
fi 

Ausgang:

$ ./test.sh --parent 
kill 2187 
./test.sh: line 10: 2187 Terminated    "$0" --child 
+0

Aktualisierte Antwort. – user000001

5
somecommand & 

gibt eine pid des Kindes in $!

somecommand & 
pid[0]=$! 
anothercommand & 
pid[1]=$! 
trap INT " kill ${pid[0]} ${pid[1]}; exit 1" 
wait 

ich mit diesem Modell beginnen würde, anstatt mit bash Auftragssteuerung (bg, fg, Jobs). Normalerweise erbt und init verwaiste Prozesse. Welches Problem versuchen Sie zu lösen?

+0

Ich weiß, dass ich das untergeordnete Skript ändern kann, um Interrupts an die Prozesse weiterzuleiten, die es hervorbringt. Ich habe mich nur gefragt, ob es möglich ist, Interrupts an Nachkommen zu senden, ohne das Child-Skript zu modifizieren. – yonran

+1

FYI: Linie 2 sollte ein $ haben! nicht $ 1 – Tully

+0

INT hat nicht für mich funktioniert, ich habe EXIT stattdessen auf OS X – Michal

8

Für alle fragen, das ist, wie Sie Childs starten in der Hintergrund und töten sie auf ctrl + c:

#!/usr/bin/env bash 
command1 & 
pid[0]=$! 
command2 & 
pid[1]=$! 
trap "kill ${pid[0]} ${pid[1]}; exit 1" INT 
wait 
+0

Dies ist nützlich, obwohl ich festgestellt habe, dass 'kill' nur die in den Argumenten angegebenen Prozesse und nicht ihre Nachkommen töten würde. – Flimm

0

Sie haltenmitmit Hintergrundaufgaben mit einem einfachen kleinen Twist: Setzen Sie Ihren asynchronen Subprozessaufruf in eine Funktion oder {}, und geben Sie setsid, so dass es eine eigene Prozessgruppe hat.

Hier ist das Skript halten es ganze erste Absicht ist:

  • mit und SIGINT propagieren und nicht von einem anderen Signal

  • Modifikation nur die Berufung mit: "$0" --child & zu { setsid "$0" --child; } &

  • Zugabe der Code, der erforderlich ist, um die PID der untergeordneten Instanz abzurufen. Dies ist der einzige Prozess in der Hintergrund-Subshell.

Hier ist der Code:

#!/bin/bash 

if [ "$1" = "--child" ]; then 
sleep 1000 

elif [ "$1" = "--parent" ]; then 
{ setsid "$0" --child; } & 
subshell_pid=$! 
pids=$(ps -ax -o ppid,pid --no-headers | 
    sed -r 's/^ +//g;s/ +/ /g' | 
    grep "^$subshell_pid " | cut -f 2 -d " "); 
for child in $pids; do 
    echo kill -SIGINT "-$child" && kill -SIGINT "-$child" 
done 
wait $subshell_pid 

else 
echo "Must be invoked with --child or --parent." 

Hier ist der wichtige doc Teil von bash Handbuch

Prozessgruppen-ID-Effekt auf den Hintergrund-Prozess (in Job Control Abschnitt doc):

[...] Prozesse w Schlauch Prozessgruppe ID ist gleich der aktuellen Klemme Prozessgruppe ID [..] erhalten Tastatur-generierte Signale wie SIGINT. Diese Prozesse stehen im Vordergrund. Hintergrundprozesse sind diejenigen, deren Prozessgruppen-ID sich von der Terminals unterscheidet; Solche Prozesse sind immun gegen Tastatur-generierte Signale.

Standardprozedur für SIGINT und SIGQUIT (in Signale Abschnitt doc):

Nicht builtin durch bash Befehle ausführen Signalroutinen auf die Werte von der Schale von der übergeordneten geerbt gesetzt. Wenn die Jobsteuerung nicht aktiv ist, ignorieren asynchrone Befehle SIGINT und SIGQUIT zusätzlich zu diesen geerbten Handlern.

und etwa Modifikation von Fallen (in trap gebautet doc):

beim Eintritt ignoriert Signale an die Schale nicht eingeklemmt oder zurückgesetzt werden kann.