Tak, bashpodobnie jak w ksh(skąd pochodzi funkcja), procesy wewnątrz substytucji procesu nie są czekane (przed uruchomieniem następnego polecenia w skrypcie).
dla <(...)jednego, to zwykle w porządku, jak w:
cmd1 <(cmd2)
powłoka będzie na nią czekać cmd1i cmd1zwykle będzie na nią czekać cmd2, czytając ją do końca pliku na potoku, który jest podstawiany, a ten koniec pliku zwykle ma miejsce, gdy cmd2umiera. To z tego samego powodu kilka muszli (nie bash) nie przeszkadza czeka na cmd2w cmd2 | cmd1.
Na cmd1 >(cmd2)ogół jednak tak nie jest, ponieważ cmd2zwykle więcej czeka na cmd1niego, więc zazwyczaj kończy się później.
Zostało to naprawione, zshponieważ czeka na cmd2to (ale nie, jeśli napiszesz je jako cmd1 > >(cmd2)i cmd1nie jest ono wbudowane, użyj {cmd1} > >(cmd2)zamiast tego jak udokumentowano ).
kshnie czeka domyślnie, ale pozwala poczekać na to z waitwbudowanym (udostępnia również pid $!, choć to nie pomaga, jeśli tak zrobisz cmd1 >(cmd2) >(cmd3))
rc(ze cmd1 >{cmd2}składnią), tak samo jak kshz tym wyjątkiem, że można uzyskać pids wszystkich procesów w tle za pomocą $apids.
es(również z cmd1 >{cmd2}) czeka na cmd2podobne w zsh, a także czeka na przekierowania cmd2w <{cmd2}procesie.
bashudostępnia pid cmd2(lub dokładniej podpowłoki, ponieważ działa cmd2w procesie potomnym tej podpowłoki, mimo że jest to ostatnia tam dostępna komenda) $!, ale nie pozwala na to czekać.
Jeśli musisz użyć bash, możesz obejść problem za pomocą polecenia, które będzie czekać na oba polecenia za pomocą:
{ { cmd1 >(cmd2); } 3>&1 >&4 4>&- | cat; } 4>&1
To sprawia, że zarówno cmd1i cmd2mają fd 3 otwarte na rurze. catbędzie czekać na EOF na drugim końcu, więc zazwyczaj tylko wyjść, gdy oba cmd1i cmd2są martwe. I powłoka będzie czekać na to catpolecenie. Można to zobaczyć jako sieć przechwytującą zakończenie wszystkich procesów w tle (możesz użyć jej do innych rzeczy rozpoczętych w tle, takich jak &, coprocs, a nawet polecenia, które same w tle, pod warunkiem, że nie zamykają wszystkich swoich deskryptorów plików, jak zwykle demony ).
Zauważ, że dzięki wspomnianemu wyżej procesowi zmarnowanej podpowłoki działa, nawet jeśli cmd2zamyka swój fd 3 (polecenia zwykle tego nie robią, ale niektóre lubią sudolub sshrobią). Przyszłe wersje bashmogą ostatecznie przeprowadzić tam optymalizację, tak jak w innych powłokach. Wtedy potrzebujesz czegoś takiego:
{ { cmd1 >(sudo cmd2; exit); } 3>&1 >&4 4>&- | cat; } 4>&1
Aby upewnić się, że jest jeszcze dodatkowy proces powłoki z otwartym fd 3 czekającym na to sudopolecenie.
Zauważ, że catnic nie przeczyta (ponieważ procesy nie piszą na swoim fd 3). Jest tylko do synchronizacji. Wykona tylko jedno read()wywołanie systemowe, które na końcu nie wróci.
Można faktycznie uniknąć uruchamiania cat, używając synchronizacji komend do synchronizacji potoku:
{ unused=$( { cmd1 >(cmd2); } 3>&1 >&4 4>&-); } 4>&1
Tym razem to powłoka zamiast cattego czyta z potoku, którego drugi koniec jest otwarty na fd 3 z cmd1i cmd2. Używamy przypisania zmiennej, więc status wyjścia cmd1jest dostępny w $?.
Lub możesz ręcznie podstawić proces, a następnie możesz nawet użyć systemu, shponieważ stałoby się to standardową składnią powłoki:
{ cmd1 /dev/fd/3 3>&1 >&4 4>&- | cmd2 4>&-; } 4>&1
zauważ jednak, jak wspomniano wcześniej, że nie wszystkie shimplementacje będą czekać cmd1po cmd2zakończeniu (choć jest to lepsze niż na odwrót). Ten czas $?zawiera status wyjścia cmd2; Choć bashand zshmake cmd1„s status wyjścia dostępne ${PIPESTATUS[0]}i $pipestatus[1]odpowiednio (patrz również pipefailopcję w kilku pocisków więc $?może zgłosić awarię elementów rurowych inne niż ostatnio)
Pamiętaj, że yashma podobne problemy z funkcją przekierowywania procesów . cmd1 >(cmd2)zostanie cmd1 /dev/fd/3 3>(cmd2)tam napisane . Ale cmd2nie jest czekany i nie można też waitna niego czekać, a jego pid również nie jest dostępny w $!zmiennej. Używałbyś tych samych obejść, co dla bash.