Strg-C mit zwei gleichzeitigen Befehlen in der Bash


15

Ich möchte zwei Befehle gleichzeitig in Bash auf einem Linux-Computer ausführen. Deshalb ./execute.shschreibe ich in mein Bash-Skript:

command 1 & command 2
echo "done"

Wenn ich jedoch das Bash-Skript anhalten und Ctrl+ drücken möchte C, wird nur der zweite Befehl angehalten. Der erste Befehl läuft weiter. Wie stelle ich sicher, dass das gesamte Bash-Skript angehalten wird? Oder wie stoppe ich auf jeden Fall beide Befehle? Weil in diesem Fall, egal wie oft ich Ctrl+ drücke, Cder Befehl weiter ausgeführt wird und ich gezwungen bin, das Terminal zu schließen.


Machen Sie die nachfolgende Frage zu einer separaten Frage und entfernen Sie sie hier. Jetzt ist es für einen Besucher unklar, ob beide Fragen beantwortet wurden oder nur die eigentliche Frage.
Zelda

Antworten:


17

Wenn Sie tippen

command 1 & command 2

das ist gleich

command 1 &
command 2

Das heißt, dies führt den ersten Befehl im Hintergrund und dann den zweiten Befehl im Vordergrund aus. Insbesondere bedeutet dies, dass Ihr echo "done"Ausdruck nach command 2Fertigstellung auch dann command 1erfolgt, wenn noch ausgeführt wird.

Sie wollen wahrscheinlich

command 1 &
command 2 &
wait
echo "done"

Dadurch werden beide Befehle im Hintergrund ausgeführt und es wird gewartet, bis beide abgeschlossen sind.


Wenn Sie STRG-C drücken, wird das SIGINT-Signal nur an den Vordergrundprozess gesendet, dh command 2in Ihrer Version oder waitin meiner Version.

Ich würde vorschlagen, eine Falle wie folgt zu setzen:

#!/bin/bash

trap killgroup SIGINT

killgroup(){
  echo killing...
  kill 0
}

loop(){
  echo $1
  sleep $1
  loop $1
}

loop 1 &
loop 2 &
wait

Mit der Falle wird das von STRG-C erzeugte SIGINT-Signal eingefangen und durch die killgroupFunktion ersetzt, die alle diese Prozesse abbricht.


Vielen Dank für Ihre Antwort! Ich habe jedoch eine Folgefrage. Ich habe jetzt das folgende Skript: trap killgroup SIGINT killgroup () {echo killing ... kill 0} befehl001 befehl1 & befehl2 Ich habe den wait-Befehl ausgelassen, da das Skript fortgesetzt werden darf, wenn befehl2 beendet ist. Es scheint jedoch, dass Befehl 1 bereits gestartet wird, wenn ich das Skript ausführe. Kann ich das beheben? Vielen Dank
maero21

Kommando1 startet direkt nach Beendigung von Kommando001. Sie können set -xam Anfang Ihres Skripts verwenden, um die ausgeführten Befehle zu drucken.
Michas

6

Wenn Sie einen Befehl aus einem Skript in den Hintergrund stellen, wird die PID nicht auf dem Bildschirm angezeigt. Sie können die eingebaute Variable verwenden, $!die die PID des letzten Prozesses speichert, damit Sie die PID von Befehl1 erfassen können.

command1 &
echo $!

würde die PID von command1 wiedergeben.

Bash bietet auch den eingebauten Trap, mit dem Sie eine Folge von Befehlen registrieren können, die ausgeführt werden sollen, wenn bestimmte Signale empfangen werden. Sie können dies verwenden, um den Befehl SIGINT und kill1 abzufangen, bevor Sie das Hauptskript beenden, z

#!/bin/bash

onINT() {
echo "Killing command1 $command1PID too"
kill -INT "$command1PID"
exit
}

trap "onINT" SIGINT
command1 &
command1PID="$!"
comamnd2
echo Done

Ctrl CWenn Sie jetzt Befehl 2 ausführen, werden durch das Drücken von Befehl1 und Befehl2 SIGINT gesendet.


Sie können auch die %nSyntax verwenden, um bestimmte Hintergrundjobs in dieser Shell zu beenden. Normalerweise müssen Sie kill %1den neuesten und einzigen Hintergrundprozess beenden. Verwenden Sie jobsbei mehr Hintergrundprozessen, um die Liste zuerst anzuzeigen.
9000

@ 9000: Ja, aber das OP führt seine Befehle in einem Skript (./execute.sh) aus. Ist es also viel problematischer, Jobs zum Laufen zu bringen?

@lain: sicherlich. Ich habe den Punkt über das Ausführen eines Skripts verpasst.
9000

5

Neuere Versionen von GNU Parallel werden tun, was Sie wollen:

parallel ::: "command 1" "command 2"
echo "done"

Oder wenn gleich commandbleibt:

parallel command ::: 1 2
echo done

Sehen Sie sich das Intro-Video an, um eine kurze Einführung zu erhalten: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

Gehen Sie durch das Tutorial (man parallel_tutorial). Du kommandierst mit Liebe dafür.


1

Ctrl + C sendet ein SIGINT-Signal an Ihren Front-Prozess command2. command1wird im Hintergrund ausgeführt und ist daher nicht vom Eingabestream betroffen.

Wenn Sie tippen command1 &, sollte bash Ihnen den Prozess "PID" geben, so etwas wie [1234]. Um diesen Vorgang abzubrechen, können Sie verwenden kill 1234. Nun, wenn Sie die PIDs von beiden command1und command2(haben, schauen Sie sichps -ef ) haben, können Sie killsie alle beenden:

kill pid1 pid2 pid3 ...

Ein kleiner Trick wäre, beide Befehle im Hintergrund auszuführen, mit:

command1 & command2 &

Bash gibt Ihnen beide PIDs, die bereit sind, getötet zu werden. Ein weiterer Trick wäre, nach command1dem Töten wieder in den Vordergrund zu treten command2:

command1 & command2
# Hit Ctrl+C : command2 terminates.

fg # Bring back command1 to foreground.
# Hit Ctrl+C again, command1 terminates.

Weitere Informationen finden Sie hier: http://linuxg.net/how-to-manage-background-and-foreground-processes/

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.