wake-up-neo.com

Bash-Befehle im Hintergrund ausführen, ohne Job- und Prozess-IDs zu drucken

Es ist ziemlich einfach, einen Prozess in bash im Hintergrund auszuführen.

$ echo "Hello I'm a background task" &
[1] 2076
Hello I'm a background task
[1]+  Done                    echo "Hello I'm a background task"

Die Ausgabe ist jedoch ausführlich. In der ersten Zeile werden die Job-ID und die Prozess-ID der Hintergrundaufgabe gedruckt, dann haben wir die Ausgabe des Befehls, schließlich haben wir die Job-ID, den Status und den Befehl, der den Job ausgelöst hat.

Gibt es eine Möglichkeit, die Ausgabe beim Ausführen einer Hintergrundaufgabe so zu unterdrücken, dass die Ausgabe genau so aussieht, als würde sie ohne das kaufmännische Und am Ende angezeigt? Dh:

$ echo "Hello I'm a background task" &
Hello I'm a background task

Der Grund, den ich frage, ist, dass ich einen Hintergrundprozess als Teil eines Befehls zum Vervollständigen von Registerkarten ausführen möchte, sodass die Ausgabe dieses Befehls nicht unterbrochen werden muss, um einen Sinn zu ergeben.

62
Alex Spurling

Nicht im Zusammenhang mit der Fertigstellung, aber Sie könnten diese Ausgabe unterdrücken, indem Sie den Aufruf in eine Subshell packen:

(echo "Hello I'm a background task" &)
76

In einigen neueren Versionen von bash und in ksh93 können Sie es mit einer Sub-Shell oder einer Prozessgruppe umgeben (d. H. { ... }).

/home/shellter $ { echo "Hello I'm a background task" & } 2>/dev/null
Hello I'm a background task
/home/shellter $
11
shellter

Aufbauend auf @shellters Antwort funktionierte dies für mich:

[email protected]:~$ { echo "Hello I'm a background task" & disown; } 2>/dev/null; sleep .1;
Hello I'm a background task
[email protected]:~$

Ich kenne die Gründe dafür nicht, erinnere mich aber an einen alten Beitrag, der verhindert, dass Bash die Prozess-IDs ausgibt.

10
Tyzoid

Aufbauend auf der obigen Antwort, wenn Sie stderr erlauben müssen, vom Befehl durchzukommen:

f() { echo "Hello I'm a background task" >&2; }
{ f 2>&3 &} 3>&2 2>/dev/null
6
pajamian

Basierend auf diese Antwort habe ich mir das Präzisere und Richtigere ausgedacht:

silent_background() {
    { 2>&3 "[email protected]"& } 3>&2 2>/dev/null
    disown &>/dev/null  # Prevent whine if job has already completed
}
silent_background date
5
Tom Hale

Entschuldigung für die Antwort auf einen alten Beitrag, aber ich denke, dies ist nützlich für andere und es ist die erste Antwort auf Google.

Ich hatte ein Problem mit dieser Methode (Subshells) und der Verwendung von 'wait'. Da ich es jedoch in einer Funktion ausgeführt habe, konnte ich Folgendes tun:

function a {
    echo "I'm background task $1"
    sleep 5
}

function b {
    for i in {1..10}; do
        a $i &
    done
    wait
} 2>/dev/null

Und wenn ich es laufen lasse:

$ b
I'm background task 1
I'm background task 3
I'm background task 2
I'm background task 4
I'm background task 6
I'm background task 7
I'm background task 5
I'm background task 9
I'm background task 8
I'm background task 10

Und es gibt eine Verzögerung von 5 Sekunden, bevor ich meine Eingabeaufforderung zurückerhalte.

4
The Tomahawk

Versuchen:

[email protected]:~$ read < <( echo "Hello I'm a background task" & echo $! )
[email protected]:~$ echo $REPLY
28677

Und Sie haben sowohl die Ausgabe als auch die PID ausgeblendet. Beachten Sie, dass Sie immer noch die PID von $ REPLY abrufen können

4
mark_infinite

Die Subshell-Lösung funktioniert, aber ich wollte auch in der Lage sein, auf die Hintergrundjobs zu warten (und am Ende nicht die Meldung "Fertig" zu erhalten). $! aus einer Subshell ist in der aktuellen interaktiven Shell nicht "wartbar". Die einzige Lösung, die für mich funktionierte, war die Verwendung meiner eigenen Wartefunktion, die sehr einfach ist:

myWait() {
  while true; do
    sleep 1; STOP=1
    for p in $*; do
      ps -p $p >/dev/null && STOP=0 && break
    done
    ((STOP==1)) && return 0
  done
}

i=0
((i++)); p[$i]=$(do_whatever1 & echo $!)
((i++)); p[$i]=$(do_whatever2 & echo $!)
..
myWait ${p[*]}

Leicht genug.

1
ExpertNoob1