Dlaczego funkcja nie powróci, dopóki proces w tle nie zakończy się?


21

Rozważ ten skrypt:

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

Skrypt nie przechodzi przez nawias zamykający, dopóki proces leafpad nie zostanie zakończony, nawet jeśli jest to proces w tle.

Dlaczego to? Czy można uruchomić proces w tle z funkcji?

Odpowiedzi:


22

Funkcja powraca, ale blokowanie podstawiania poleceń, ponieważ utworzyłeś zadanie w tle, ale nadal masz otwarte standardowe wyjście fd. Po prostu zamknij, dodając >/dev/nullprzed &.

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

Jeśli chcesz, aby Twój proces miał również stdin, stdout, stderr zamknięty, użyj tego:

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

Spowoduje to zamknięcie stdin (0), stdout (1) i stderr (2), a następnie tła (&). Ponadto, gdy korzystasz z tych przekierowań strumienia , nie zapominaj, że są one „kopiowane”, co oznacza duplikowanie w kolejności wykonywania.

1>/dev/null 2>&1

i

2>&1 1>/dev/null

nie są takie same ! W pierwszym przypadku duplikujesz strumień do / dev / null (co jest tym, czego chcesz), w drugim przypadku kopiujesz / dev / stdout do stderr, a następnie zamykasz stdout. Tak więc każda wysłana wiadomość stderrpojawi się w konsoli.


Potwierdzono w moim systemie
120161

10
Nie zamykasz strumieni, przekierowujesz je.
dcat

4
zamknąć; n>&-gdzie njest deskryptor pliku.
dcat

1
@dcat: Tak, ale przekierowanie do / z /dev/nullnie prowadzi do błędów we / wy, gdy proces próbuje zapisać swoje standardowe wyjście, ale stwierdza, że 1jest to nieprawidłowy FD. Więc terminologia w poście jest nieprawidłowa, a nie faktyczne programowanie bash. (W rzeczywistości powielenie FD 1 na 0 oznacza, że ​​stdin będzie deskryptorem pliku otwieranym O_RDONLY, co prawdopodobnie da błąd (zamiast pożądanego braku bajtów), gdy proces spróbuje odczytać.) Np. wc >/dev/null 0>&1->wc: standard input: Bad file descriptor
Peter Cordes,

1
@PeterCordes - Zamknięcie starego deskryptora i przekierowanie nowego nie musi się wykluczać. exec <&- >&- <>/dev/null >&0obsługuje stdin / out dość wyczerpująco. To robi różnicę zshprzynajmniej w tym, co połączy automatycznie wszystkie otwarcia tego samego deskryptora, gdy ustawiony jest multios.
mikeserv
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.