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
Odpowiedzi:
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,ps
czygrep
zaczyna 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
zaczyna wyświetlać pasujące linie dużymi literami, nawet zanim
grep
zakończy przeglądanie dużego pliku.wyświetla pierwszą pasującą linię i może przestać przetwarzać na długo przed
grep
zakoń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ą.
źródło
grep
, a bufor jest zarządzany przez jądro w samym potoku. W przypadku tego drugiego zobacz Jak duży jest bufor bufora?Kolejność uruchamiania poleceń nie ma znaczenia i nie jest gwarantowana. Nie wdając się w szczegóły wtajemniczeń
pipe()
,fork()
,dup()
iexecve()
, 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.źródło
Wydaje się, że istnieje ryzyko, że zostanie pokonany martwy koń
jest równa
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
B
był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_string
B
A
źródło
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?
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:
raz pokaż
grep
i / lubps
polecenie, a następnie teraz. Zależy to od tego, jak szybko jądro naprawdę uruchomi procesy przy użyciu funkcji exec systemu.źródło
exec()
, ale jak przeplataneexec()
są wywołania i wykonywanie programów w potoku .