Warum wird die Funktion erst wieder ausgeführt, wenn der Hintergrundprozess beendet ist?


21

Betrachten Sie dieses Skript:

#!/bin/bash
function start {
  leafpad &
  echo $!
}
PID=$(start)
echo "PID is $PID"

Das Skript wird erst fortgesetzt, wenn der Leafpad-Prozess beendet ist, obwohl es sich um einen Hintergrundprozess handelt.

Warum ist das? Ist es möglich, einen Hintergrundprozess von einer Funktion aus zu starten?

Antworten:


22

Die Funktion kehrt zurück, aber die Befehlsersetzung wird blockiert, da Sie einen Hintergrundjob erstellt haben, Ihr stdout fd aber immer noch geöffnet ist. Schließen Sie es einfach durch Hinzufügen >/dev/nullvor dem &.

#!/bin/bash
function start {
  leafpad >/dev/null &
  echo $!
}
PID=$(start)
echo "PID is $PID"

Wenn Ihr Prozess auch stdin, stdout, stderr closed haben soll, verwenden Sie Folgendes:

leafpad >/dev/null 0>&1 2>&1 &

Dadurch werden stdin (0), stdout (1) und stderr (2) und dann background (&) geschlossen. Wenn Sie diese Stream-Umleitungen verwenden, vergessen Sie nicht, dass sie "getäuscht" sind, dh in der Reihenfolge der Ausführung dupliziert.

1>/dev/null 2>&1

und

2>&1 1>/dev/null

sind nicht das Gleiche ! Im ersten Fall duplizieren Sie einen Stream nach / dev / null (was Sie wollen), im zweiten Fall duplizieren Sie / dev / stdout nach stderr und schließen dann stdout. Daher wird jede Nachricht, an die gesendet stderrwird, in Ihrer Konsole angezeigt.


Auf meinem System bestätigt
— user120161

10
Sie schließen die Streams nicht, sondern leiten sie um.
— dcat

4
schließen; n>&-Wo nist der Dateideskriptor?
— dcat

1
@dcat: Ja, aber die Umleitung zu / von /dev/nullführt nicht zu E / A-Fehlern, wenn ein Prozess versucht, seine Standardausgabe zu schreiben, aber feststellt, dass dies 1eine ungültige FD ist. Die Terminologie im Beitrag ist also falsch, nicht die eigentliche Bash-Programmierung. (Tatsächlich bedeutet das Duplizieren von FD 1 auf 0, dass stdin ein Dateideskriptor ist, mit O_RDONLYdem geöffnet wird , und der wahrscheinlich einen Fehler (statt der gewünschten Anzahl von verfügbaren Bytes) ausgibt, wenn der Prozess versucht zu lesen.) ZB wc >/dev/null 0>&1->wc: standard input: Bad file descriptor
— Peter Cordes

1
@PeterCordes - Das Schließen des alten Deskriptors und das Umleiten des neuen müssen sich nicht gegenseitig ausschließen. exec <&- >&- <>/dev/null >&0geht ziemlich ausführlich mit stdin / out um. Es macht zshzumindest einen Unterschied, welche Art der Verkettung alle Öffnungen auf demselben Deskriptor automatisch ausführt, wenn Multios festgelegt werden.
— mikeserv
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.