W jakiej kolejności działają polecenia potokowe?


89

Nigdy tak naprawdę nie myślałem o tym, jak powłoka faktycznie wykonuje polecenia potokowe. Zawsze mówiono mi, że „standardowe wyjście jednego programu jest przesyłane do wejścia innego standardowego”, jako sposób myślenia o rurach. Więc naturalnie pomyślałem, że w przypadku powiedzmy A | B, A uruchamia się jako pierwsze, a następnie B pobiera standardowe wyjście A i używa standardowego wejścia A jako wejścia.

Zauważyłem jednak, że kiedy ludzie szukają określonego procesu w ps, dołączają grep -v „grep” na końcu polecenia, aby upewnić się, że grep nie pojawia się w końcowym wyniku. Oznacza to, że w poleceniu ps aux | grep "bash" | grep -v "grep", co oznacza, że ​​ps wiedział, że grep jest uruchomiony i dlatego jest w wyniku ps. Ale jeśli ps zakończy działanie, zanim jego dane wyjściowe zostaną przekazane do grep, to skąd wiedział, że grep działa?

flamingtoast@FTOAST-UBUNTU: ~$ ps | grep ".*"
PID TTY          TIME CMD
3773 pts/0    00:00:00 bash
3784 pts/0    00:00:00 ps
3785 pts/0    00:00:00 grep

dlaczego nie zaakceptować odpowiedzi?
— törzsmókus

Odpowiedzi:


64

Polecenia potokowe są uruchamiane jednocześnie. Kiedy biegniesz ps | grep …, to szczęście losowania (lub kwestia szczegółów działania powłoki w połączeniu z dopracowaniem harmonogramu głęboko w trzewiach jądra) co do tego, psczy grepzaczyna się najpierw, a w każdym razie nadal wykonać jednocześnie.

Jest to bardzo często używane, aby umożliwić drugiemu programowi przetwarzanie danych wychodzących z pierwszego programu, zanim pierwszy program zakończy działanie. Na przykład

grep pattern very-large-file | tr a-z A-Z

zaczyna wyświetlać pasujące linie dużymi literami, nawet zanim grepzakończy przeglądanie dużego pliku.

grep pattern very-large-file | head -n 1

wyświetla pierwszą pasującą linię i może przestać przetwarzać na długo przed grepzakończeniem odczytu pliku wejściowego.

Jeśli czytasz gdzieś, że programy potokowe działają w sekwencji, uciekaj od tego dokumentu. Programy potokowe działają jednocześnie i zawsze mają.


7
I fajne w tym przykładzie jest to, że gdy głowa dostaje jedną linię, której potrzebuje, kończy się, a gdy grep to zauważy, kończy się również bez wykonywania dodatkowej pracy za darmo.
— Joe

Wydaje mi się, że istnieje jakiś bufor IO dotyczący potoku ... skąd mam wiedzieć, że ma rozmiar w bajtach? Co chcę przeczytać, aby dowiedzieć się więcej na ten temat? :)
— n611x007

3
@naxa Właściwie istnieją dwa bufory. W programie znajduje się bufor stdiogrep , a bufor jest zarządzany przez jądro w samym potoku. W przypadku tego drugiego zobacz Jak duży jest bufor bufora?
— Gilles

49

Kolejność uruchamiania poleceń nie ma znaczenia i nie jest gwarantowana. Nie wdając się w szczegóły wtajemniczeń pipe(), fork(), dup()i execve(), powłoki najpierw tworzy rurę, przewód dla danych, które będą przepływać pomiędzy procesami, a następnie tworzy procesy z końcami rury połączonej z nimi. Pierwszy uruchomiony proces może blokować oczekiwanie na dane wejściowe z drugiego procesu lub blokować oczekiwanie na rozpoczęcie przez drugi proces odczytu danych z potoku. Te oczekiwania mogą być dowolnie długie i nie mają znaczenia. Bez względu na kolejność uruchamiania procesów dane są ostatecznie przesyłane i wszystko działa.


5
Dobra odpowiedź, ale OP wydaje się sądzić, że procesy przebiegają sekwencyjnie. Możesz tu wyjaśnić, że procesy są uruchamiane jednocześnie, a rura jest jak ... rura między wiadrami, w której woda przepływa przez cały czas (w przybliżeniu).
— Keith

Dziękuję za wyjaśnienie. Źródła, które czytałem, sprawiały wrażenie, jakby programy potokowe były uruchamiane sekwencyjnie, a nie jednocześnie.
— action_potato

Aby zobaczyć proces rozpoczynający się w nieokreślony sposób, spróbuj uruchomić to 1000 razy: echo -na> & 2 | echo b> i 2
— Ole Tange

28

Wydaje się, że istnieje ryzyko, że zostanie pokonany martwy koń

    A | b

jest równa

    > Temporary_file 
    B < temporary_file 
    rm temporary_file

Ale kiedy powstał Unix i dzieci jeździły do ​​szkoły dinozaury, dyski były bardzo małe i często dość łagodne polecenie zajmowało całą wolną przestrzeń w systemie plików. Gdyby Bbyło coś takiego , końcowy wynik potoku mógłby być znacznie mniejszy niż ten plik pośredni. Dlatego też, rura została rozwinięta, a nie jako skrótowy zapis „run pierwszy, a następnie uruchomić B przy udziale A jest wyjściowy” modelu, a jako sposób , aby wykonać równocześnie z i eliminują potrzebę przechowywania plików pośrednią na dysku.grep some_very_obscure_stringBA


2
To odpowiada dlaczego i dlatego otrzymuję mój głos.
— LIttle Ancient Forest Kami

1

Zazwyczaj uruchamiasz to w bash. proces działa i uruchamia się jednocześnie, ale działa równolegle przez powłokę. Jak to jest możliwe?

  1. jeśli nie jest to ostatnie polecenie w potoku, utwórz potok bez nazwy z parą gniazd
  2. widelec
  3. w potomku przypisz stdin / stdout do gniazd, jeśli jest to potrzebne (dla pierwszego procesu w potoku stdin nie jest ponownie przypisany, to samo dla ostatniego procesu i jego standardu)
  4. w podrzędnym EXEC podano polecenie z argumentami, które usuwają oryginalny kod powłoki, ale pozostawiają wszystkie otwarte gniazda. Identyfikator procesu potomnego nie zostanie zmieniony, ponieważ jest to ten sam proces potomny
  5. jednocześnie z dzieckiem, ale równolegle pod główną powłoką, przejdź do kroku 1.

system nie gwarantuje, jak szybko zostanie wykonane exec i rozpocznie się uruchamianie określonej komendy. jest niezależny od powłoki, ale system. To dlatego, że:

ps auxww| grep ps | cat

raz pokaż grepi / lub pspolecenie, a następnie teraz. Zależy to od tego, jak szybko jądro naprawdę uruchomi procesy przy użyciu funkcji exec systemu.


1
Równoczesne wykonywanie oznacza, że ​​dwa lub więcej procesów wykonuje się w tym samym przedziale czasowym, zwykle z pewną zależnością między nimi. Równoległe wykonywanie oznacza, że ​​dwa lub więcej procesów wykonuje się jednocześnie (np. Na osobnych rdzeniach procesora w tym samym czasie). Równoległość nie jest istotna dla pytania, ani nie jest wykonywane „jak szybko” exec(), ale jak przeplataneexec() są wywołania i wykonywanie programów w potoku .
— Thomas Nyman
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.