Wie kann ich in einem Shell-Skript (1) einen Befehl im Hintergrund starten (2) x Sekunden warten (3) einen zweiten Befehl ausführen, während dieser Befehl ausgeführt wird?

11

Das muss ich tun:

  1. Starten Sie Prozess A im Hintergrund
  2. Warten Sie x Sekunden
  3. Starten Sie Prozess B im Vordergrund

Wie kann ich das Warten ermöglichen?

Ich sehe, dass 'Schlaf' alles zum Stillstand zu bringen scheint und ich nicht wirklich 'warten' möchte, bis Prozess A vollständig abgeschlossen ist. Ich habe einige zeitbasierte Schleifen gesehen, aber ich frage mich, ob es etwas saubereres gibt.

Julie
quelle
4
Ich schlage vor, dass Sie diese Frage erweitern, indem Sie ein einfaches Beispiel dafür geben, was Sie bereits versucht haben.
Andy Dalton
10
Woher kommt der Eindruck, dass sleepProzess A angehalten wird? Können Sie den von Ihnen verwendeten Testprozess anzeigen oder eine Ausgabe anzeigen, die dies anzeigt? Wenn Prozess A angehalten wird , ist es wahrscheinlicher, dass er versucht, vom Terminal zu lesen, während er im Hintergrund ausgeführt wird und aus diesem Grund angehalten wird, anstatt irgendetwas damit zu tun sleep.
Charles Duffy
3
... wenn das ist der Fall, process_a </dev/null &wird befestigen seine stdin /dev/nullanstatt die TTY, und dass ausreichend sein kann , um das Problem zu vermeiden.
Charles Duffy
Meiner Erfahrung nach blockiert der Schlaf nur den aktuellen Prozess und damit nicht den Prozess, der zuvor im Hintergrund mit &
MADforFUNandHappy

Antworten:

28

Wenn ich Ihre Frage nicht falsch verstehe, kann sie einfach mit diesem kurzen Skript erreicht werden:

#!/bin/bash

process_a &
sleep x
process_b

(und fügen Sie waitam Ende ein zusätzliches hinzu, wenn Ihr Skript process_avor dem Beenden auf den Abschluss warten soll ).

Sie können dies sogar als Einzeiler tun, ohne dass ein Skript erforderlich ist (wie von @BaardKopperud vorgeschlagen):

process_a & sleep x ; process_b
dr01
quelle
6
Beachten Sie, dass Sie dies nicht benötigen bash. Jede Shell, einschließlich der Ihres Systems sh, muss also keine Abhängigkeit von Bash für Ihr Skript hinzufügen.
Stéphane Chazelas
4
Oder einfach: process_a & sleep x; process_b
Baard Kopperud
9

Sie können den Hintergrundsteuerungsoperator (&) verwenden , um einen Prozess im Hintergrund auszuführen, und den sleepBefehl , um zu warten, bevor ein zweiter Prozess ausgeführt wird, dh:

#!/usr/bin/env bash
# script.sh

command1 &
sleep x
command2

Hier ist ein Beispiel für zwei Befehle, die einige zeitgestempelte Nachrichten ausdrucken:

#!/usr/bin/env bash

# Execute a process in the background
echo "$(date) - Running first process in the background..."
for i in {1..1000}; do
    echo "$(date) - I am running in the background";
    sleep 1;
done &> background-process-output.txt &

# Wait for 5 seconds
echo "$(date) - Sleeping..."
sleep 5 

# Execute a second process in the foreground
echo "$(date) - Running second process in the foreground..."
for i in {1..1000}; do
    echo "$(date) - I am running in the foreground";
    sleep 1;
done

Führen Sie es aus, um zu überprüfen, ob es das gewünschte Verhalten aufweist:

user@host:~$ bash script.sh

Fri Dec  1 13:41:10 CST 2017 - Running first process in the background...
Fri Dec  1 13:41:10 CST 2017 - Sleeping...
Fri Dec  1 13:41:15 CST 2017 - Running second process in the foreground...
Fri Dec  1 13:41:15 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:16 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:17 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:18 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:19 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:20 CST 2017 - I am running in the foreground
...
...
...
igal
quelle
2
Die Frage lautet "Prozess B im Vordergrund starten ".
Sparhawk
1
@ Sparhawk Wow. Völlig falsch verstanden - keine Erklärung. Danke für das Heads-up - Code korrigiert. Ernsthafte Nostalgie von Ihrem Benutzernamen, übrigens.
2.
1
Keine Bange! (Auch der Benutzername war ursprünglich ein Hinweis auf diesen Kerl , aber ich erkannte erst später, dass es sich um einen Eddings-Charakter handelte! Und ich möchte diese Bücher noch einmal lesen…)
Sparhawk
5

Ich mag die Antwort von @ dr01, aber er überprüft den Exit-Code nicht und Sie wissen nicht, ob Sie erfolgreich waren oder nicht.

Hier ist eine Lösung, die die Exitcodes überprüft.

#!/bin/bash

# run processes
process_a &
PID1=$!
sleep x
process_b &
PID2=$!
exitcode=0

# check the exitcode for process A
wait $PID1    
if (($? != 0)); then
    echo "ERROR: process_a exited with non-zero exitcode" >&2
    exitcode=$((exitcode+1))
fi

# check the exitcode for process B
wait $PID2
if (($? != 0)); then
    echo "ERROR: process_b exited with non-zero exitcode" >&2
    exitcode=$((exitcode+1))
fi
exit ${exitcode}

Normalerweise speichere ich die PIDs in einem Bash-Array und dann ist die PID-Prüfung eine for-Schleife.

Trevor Boyd Smith
quelle
2
Möglicherweise möchten Sie diese Exit-Codes im Exit-Status Ihres Skripts wieA & sleep x; B; ret=$?; wait "$!" || exit "$ret"
Stéphane Chazelas
1
@ StéphaneChazelas gute Idee. Ich habe den Code aktualisiert, um sicherzustellen, dass ein Exitcode ungleich Null zurückgegeben wird, wenn einer oder beide fehlschlagen.
Trevor Boyd Smith
Das OP will process_bim Vordergrund laufen. Vermutlich process_akönnte das Programm beendet werden, während process_bes ausgeführt wird, aber Sie können es trotzdem waitabrufen und den Beendigungsstatus erhalten, nachdem Sie den Beendigungsstatus des Vordergrunds auf process_bnormale Weise mit $?direkt erfasst haben .
Peter Cordes