Zgodnie z jego dokumentacją, bash czeka, aż wszystkie polecenia w potoku zakończą działanie, zanim przejdzie dalej
Powłoka czeka na zakończenie wszystkich poleceń w potoku przed zwróceniem wartości.
Dlaczego więc polecenie yes | true
kończy się natychmiast? Czy yes
pętla nie powinna być wieczna i spowodować, że rurociąg nigdy nie powróci?
I podpytanie: zgodnie ze specyfikacją POSIX potoki powłoki mogą powrócić po zakończeniu ostatniego polecenia lub poczekać, aż wszystkie polecenia zakończą się. Czy zwykłe muszle zachowują się inaczej w tym sensie? Czy są jakieś muszle, w których yes | true
zapętla się na zawsze?
yes | tee >(true) >/dev/null
zrobi tak, jak się spodziewasz, taktee
dalej, dopóki wszyscy pisarze nie umrą, więctrue
odejście nie zakłóci ich całkowicie.true
jest w zasadzie{return 0;}
programem, więc nie spodziewałbym się, że będzie działał długo, nie mówiąc już o wieczności.Odpowiedzi:
Po
true
wyjściu strona odczytu potoku jest zamknięta, aleyes
kontynuuje próbę zapisu po stronie zapisu. Ten warunek nazywany jest „zepsutą rurą” i powoduje, że jądro wysyłaSIGPIPE
sygnał doyes
. Ponieważyes
nic specjalnego w tym sygnale nie zostanie zabite, zostanie zabity. Jeśli zignoruje sygnał, jegowrite
wywołanie zakończy się niepowodzeniem z kodem błęduEPIPE
. Programy, które to robią, muszą być przygotowane do zauważeniaEPIPE
i zaprzestania pisania, w przeciwnym razie przejdą w nieskończoną pętlę.Jeśli zrobisz
strace yes | true
1 , zobaczysz, że jądro przygotowuje się do obu możliwości:strace
obserwuje zdarzenia za pośrednictwem interfejsu API debugera, który najpierw informuje go o powrocie wywołania systemowego z błędem, a następnie o sygnale. Zyes
„s perspektywy, choć zdarza się pierwszy sygnał. (Technicznie sygnał jest dostarczany po tym, jak jądro zwróci kontrolę w przestrzeni użytkownika, ale przed wykonaniem kolejnych instrukcji maszyny, więc funkcjawrite
„otoki” w bibliotece C nie ma szans na ustawienieerrno
i powrót do aplikacji.)1 Niestety,
strace
jest specyficzny dla Linuksa. Większość współczesnych Uniksów ma jakieś polecenie, które robi coś podobnego, ale często ma inną nazwę, prawdopodobnie nie dekoduje argumentów syscall tak dokładnie, a czasami działa tylko dla roota.źródło
yes
jest podłączone do potoku.yes
uzyskanie SIGPIPE, ponieważ FD, do którego pisze, nie jest podłączony do potoku.yes >/dev/null
zawsze. Nic nie pokazuje w potokach, co nie jest prawdą również w przypadku prostych poleceń (jak wskazuje zachowanie oczekiwania na zakończenie, również w przypadku prostych poleceń).write()
(funkcja w libc) nie powraca (przekazuje kontrolę do komputera po nim) aż do procedura obsługi sygnałów została uruchomiona, ale ponieważ procedura obsługi sygnału kończy program, sterowanie nigdy nie jest przekazywane, a zatemwrite()
nigdy nie powraca. Tak, jest to zaimplementowane w jądrze przezxxx_write()
powrót funkcji-EPIPE
, ale debugujemy program przestrzeni użytkownika i nie jesteśmy tym zainteresowani.Mało prawdopodobne, ponieważ
yes
polecenie korzysta z potoku i zakończy się niepowodzeniem po zerwaniu potoku.sleep
z drugiej strony nie używa potoku, więc:będzie działać przez co najmniej 100000000 sekund.
źródło
true
jest wbudowane. Odnosi się to do ostatnich wersjachBourne Shell
,ksh93
,zsh
. Jeśli naciśniesz,^Z
gdy takie polecenie jest uruchomione, spowoduje to zawieszenie uśpienia, a powłoka nigdy nie będzie mogła się zregenerować bez pomocy z zewnątrz.sbrk()
. Przenośna i utrzymana wersja znajduje się w pakiecie narzędzi schily, a @Charles Duffy już odkrył lokalizację dla informacji ;-)bsh
przeniosłem z powrotem do Bourne Shell, pochodzi z mojego systemu (Berthold Shell z VBERTOS, wersja UNOS z ulepszoną pamięcią wirtualną - pierwszy klon UNIX). Bsh dostał wiele funkcji csh w 1984 i 1985 roku, ale mechanizm aliasów z UNOS był lepszy niż ten z csh już w 1980 roku. Inne nowe funkcje Bourne Shell pochodzą z POSIX, aby umożliwić osiągnięcie zgodności z POSIX.