Jak bash traktuje „>> ()”

9

Podczas eksperymentów z przekierowaniem wyjścia i podstawieniem procesu natknąłem się na następującą komendę i jej wynik:

    me @ elem: ~ $ echo foo>> (cat); pasek echa
    bar
    me @ elem: ~ $ foo

(Tak, ta pusta nowa linia na końcu jest celowa).

Więc uderz w pasek echa, wypisuje mój zwykły monit, echo foo, echo jest nową linią i pozostawia tam mój kursor. Jeśli ponownie wcisnę Enter, wydrukuje mój monit w nowym wierszu i pozostawi kursor za nim (zgodnie z oczekiwaniami, gdy ktoś uderzy Enter w pustym wierszu poleceń).

Spodziewałem się, że napisze foo do deskryptora pliku, cat czyta foo i echo, pasek drugiego echa, a następnie wraca do wiersza poleceń. Ale oczywiście tak nie jest.

Czy ktoś mógłby wyjaśnić, co się dzieje?

Stanley Yu
źródło
Chciałbym zasugerować znalezienie odpowiedzi na ten temat: unix.stackexchange.com/questions/182800/... Wyjaśnia podwójne przekierowanie i wyjaśnia, dlaczego kończysz z różnymi wynikami. Zarówno Muru, jak i Michael Hormers.
No Time,
Aby dowiedzieć się, dlaczego wynik zastąpienia procesu pojawia się po monicie (a w niektórych okolicznościach nie pojawia się wcale) w niektórych wersjach powłoki Bourne Again, zobacz unix.stackexchange.com/questions/471987 .
JdeBP

Odpowiedzi:

9

Może być foowyświetlany przed bar, po bar, a nawet po monicie, w zależności od czasu. Dodaj małe opóźnienie, aby uzyskać spójny czas:

$ echo foo > >(sleep 1; cat); echo bar; sleep 2 
bar
foo
$

barpojawia się natychmiast, potem foopo jednej sekundzie, a następnie kolejny monit po kolejnej sekundzie.

Dzieje się tak, że bash wykonuje podstawienia procesów w tle.

  1. Główny proces bash uruchamia podpowłokę do wykonania sleep 1; cati ustawia do niej potok.
  2. Wykonywany jest główny proces bash echo foo. Ponieważ nie zapełnia to bufora potoku, echopolecenie kończy się bez blokowania.
  3. Wykonywany jest główny proces bash echo bar.
  4. Główny proces bash uruchamia polecenie sleep 2.
  5. Tymczasem podpowłoka uruchamia polecenie sleep 1.
  6. Po około 1 sekundzie sleep 1wraca do podprocesu. Podproces przechodzi do wykonania cat.
  7. cat kopiuje dane wejściowe na dane wyjściowe (wyświetlane na ekranie) i zwraca.
  8. Podkładka zakończyła pracę, wychodzi.
  9. Po kolejnej sekundzie sleep 2wraca. Proces powłoki głównej kończy się i pojawia się następny monit.
Gilles „SO- przestań być zły”
źródło
3

Nie potrzebujesz substytucji procesu, aby uzyskać ten efekt. Spróbuj tego:

( echo foo | cat & )

Otrzymasz ten sam wynik (bez bar; zostawię to jako ćwiczenie) i z tego samego powodu. W obu przypadkach catjest uruchamiany jako zadanie w tle. W mojej linii tutaj jest to jednoznaczne. W przypadku podstawienia procesu jest on również jawny - jest to osobny proces dołączony do deskryptora pliku nazwy - ale być może nie jest tak oczywisty.

Proces potomny niekoniecznie kończy się przed bashwydrukowaniem następnego monitu. A ponieważ jego dane wyjściowe są buforowane, nic nie wysyła, dopóki się nie zakończy. W tym momencie bash właśnie drukował $na stderr, a teraz proces w tle kończy się po wydrukowaniu fooi nowej linii.

rici
źródło