Dwa okna, ten sam użytkownik, z monitami bash. W oknie typu 1:
$ mkfifo f; exec <f
Więc bash próbuje teraz odczytać z deskryptora pliku 0, który jest odwzorowany na nazwany potok f
. W oknie typu 2:
$ echo ls > f
Teraz okno-1 wypisuje ls, a następnie powłoka umiera. Dlaczego?
Następny eksperyment: ponownie otwórz okno-1 za pomocą exec <f
. W oknie typu 2:
$ exec 3>f
$ echo ls >&3
Po pierwszym wierszu powyżej okno-1 budzi się i wyświetla monit. Dlaczego? Po drugim wierszu powyżej okno-1 drukuje dane ls
wyjściowe, a powłoka pozostaje przy życiu. Dlaczego? W rzeczywistości, teraz w oknie-2, echo ls > f
nie zamyka powłoki okna-1.
Odpowiedź musi mieć związek z istnieniem deskryptora pliku 3 z okna-2 odwołującego się do nazwanego potoku ?!
file-descriptors
fifo
Fixee
źródło
źródło
exec <f
,bash
nie próbuje odczytać zf
, to jest najpierw próbuje otworzyć go.open()
Nie wróci, dopóki istnieje jakiś inny sposób robi się w trybie zapisu do rury (w którym momencie rura zostanie instancja, a powłoka będzie czytać wejście z nią).exec 3>f
uruchomieniu pierwsza powłoka wyświetla monit. (Drobny punkt, czy miałeś na myśli „w trybie pisania ” w swoim komentarzu?)Odpowiedzi:
Ma to związek z zamknięciem deskryptora pliku.
W pierwszym przykładzie
echo
zapisuje w swoim standardowym strumieniu wyjściowym, który powłoka otwiera, aby się z nią połączyćf
, a po zakończeniu deskryptor jest zamykany (przez powłokę). Po stronie odbierającej powłoka, która odczytuje dane wejściowe ze standardowego strumienia wejściowego (podłączonegof
), odczytujels
, uruchamia się,ls
a następnie kończy z powodu stanu końca pliku na swoim standardowym wejściu.Występuje warunek końca pliku, ponieważ wszyscy autorzy nazwanego potoku (tylko jeden w tym przykładzie) zamknęli swój koniec potoku.
W drugim przykładzie
exec 3>f
otwiera deskryptor pliku 3 do zapisuf
, a następnieecho
zapisujels
w nim. To powłoka, która ma teraz otwarty deskryptor pliku, a nieecho
polecenie. Deskryptor pozostaje otwarty, dopóki tego nie zrobiszexec 3>&-
. Po stronie odbierającej powłoka, która odczytuje dane wejściowe ze swojego standardowego strumienia wejściowego (podłączonego dof
), odczytujels
, działa,ls
a następnie czeka na więcej danych wejściowych (ponieważ strumień jest nadal otwarty).Strumień pozostaje otwarty, ponieważ wszyscy piszący do niego (powłoka, poprzez
exec 3>f
iecho
) nie zamknęli końca potoku (exec 3>f
nadal działa).Pisałem o tym
echo
wyżej, jakby to było polecenie zewnętrzne. Najprawdopodobniej jest wbudowany w powłokę. Efekt jest taki sam.źródło
Nie ma w tym nic wielkiego: gdy nie ma programów zapisujących do potoku, wygląda na zamknięty dla czytelników, tzn. Zwraca EOF podczas odczytu i blokuje po otwarciu.
Ze strony podręcznika systemu Linux (
pipe(7)
ale zobacz takżefifo(7)
):Zamykanie końca zapisu jest tym, co niejawnie dzieje się na końcu
echo ls >f
, a jak mówisz, w innym przypadku deskryptor pliku pozostaje otwarty.źródło
Po przeczytaniu dwóch odpowiedzi z @Kusalananda i @ikkachu, myślę, że rozumiem. W oknie-1 powłoka czeka, aż coś otworzy koniec zapisu potoku, a następnie go zamknie. Po otwarciu końca zapisu powłoka w oknie-1 drukuje monit. Gdy koniec zapisu zostanie zamknięty, powłoka otrzymuje EOF i umiera.
Po stronie okna-2 mamy dwie sytuacje opisane w moim pytaniu: w pierwszej sytuacji z
echo ls > f
, nie ma deskryptora pliku 3, więc mamyecho
spawnowanie, i tostdin
istdout
wygląda tak:Następnie
echo
kończy się, a powłoka zamyka oba deskryptory. Ponieważ deskryptor pliku 1 jest zamknięty i zawiera odwołaniaf
, koniec zapisuf
jest zamknięty, co powoduje EOF dla okna-1.W drugiej sytuacji działamy
exec 3>f
w naszej powłoce, powodując, że powłoka przyjmuje następujące środowisko:Teraz uruchamiamy,
echo ls >& 3
a powłoka przydziela deskryptory plikówecho
w następujący sposób:Następnie powłoka zamyka trzy powyższe deskryptory, w tym
f
, alef
nadal ma do niej odniesienie z samej powłoki. To jest ważna różnica.exec 3>&-
Jak zauważył @Kusalananda, zamknięcie deskryptora 3 za pomocą zamknęłoby ostatnie otwarte odwołanie i spowodowałoby EOF dla okna-1.źródło