Czy narzędzia Linux są inteligentne podczas uruchamiania poleceń potokowych?

23

Właśnie uruchomiłem kilka poleceń w terminalu i zacząłem się zastanawiać, czy Unix / Linux używa skrótów podczas uruchamiania poleceń potokowych?

Załóżmy na przykład, że mam plik zawierający milion wierszy, z których pierwsze 10 zawiera hello world. Jeśli uruchomisz polecenie, grep "hello world" file | headczy pierwsze polecenie zatrzyma się, gdy tylko znajdzie 10 wierszy, czy też najpierw przeszuka cały plik?

DisgruntledGoat
źródło
2
Właśnie dlatego gnu grep ma -margument.
Paul Tomblin,
3
Terminal nie ma z tym nic wspólnego. Poleceniami potokowymi zarządza powłoka.
Keith Thompson,
@KeithThompson wybacz moją ignorancję, nie jestem wielka w terminologii, nie byłam pewna, czy nazwać to terminalem, powłoką czy wierszem poleceń. Nie krępuj się zasugerować zmiany do mojego pytania :)
DisgruntledGoat

Odpowiedzi:

30

Raczej. Powłoka nie ma pojęcia, co zrobią uruchomione polecenia, po prostu łączy dane wyjściowe jednego z danymi wejściowymi drugiego.

Jeśli grepznajdzie więcej niż 10 wierszy z napisem „hello world”, wówczas headbędzie mieć wszystkie 10 wierszy, które chce, i zamknie potok. Spowoduje to grepzabicie SIGPIPE, więc nie trzeba kontynuować skanowania bardzo dużego pliku.

psusi
źródło
2
Sądzę więc, że z powodu warunków wyścigowych grep mógł odczytać już jedenasty lub dwunasty wzór, ale prawdopodobnie nie 100 tysięcy?
użytkownik nieznany
3
Zależy to częściowo od długości linii i wielkości bufora potoku, ale krótka odpowiedź jest taka, że ​​grep odczyta pewną ograniczoną ilość dodatkowych danych przed zabiciem.
dmckee,
1
Dokładnie @użytkownik.
psusi
Fajnie, nie wiedziałem, że to się stało. Myślałem, grepże nadal wysyłam dane wyjściowe do pustki, podobnie jak/dev/null
Izkata
15

Gdy program próbuje zapisać do potoku, a proces nie odczytuje z tego potoku, program piszący odbiera sygnał SIGPIPE . Domyślnym działaniem, gdy program odbierze SIGPIPE, jest zakończenie programu. Program może zignorować sygnał SIGPIPE, w którym to przypadku zapis zwraca błąd ( EPIPE).

W twoim przykładzie oto oś czasu tego, co się dzieje:

  • grepihead polecenia uruchomienia równoległego.
  • grep odczytuje dane wejściowe i rozpoczyna ich przetwarzanie.
  • W pewnym momencie, grep produkuje pierwszy fragment danych wyjściowych.
  • head czyta ten pierwszy fragment i zapisuje go.
  • Zakładając, że po pierwszych 10 dopasowaniach jest wystarczająca liczba linii (w przeciwnym razie grepmoże zakończyć się jako pierwsza), ostatecznie headwydrukuje żądaną liczbę linii. W tym momencie headwychodzi.
  • W zależności od względnej prędkości procesów grepi head, grepmogły zgromadzić pewne dane i jeszcze ich nie wydrukować. W momencie headwyjścia grepmoże odczytywać dane wejściowe lub przetwarzać wewnętrznie, w którym to przypadku będzie kontynuować.
  • Wkrótce grepwypisze przetwarzane dane. W tym momencie otrzyma SIGPIPE i umrze.

Prawdopodobnie grepprzetworzy nieco więcej danych niż jest to absolutnie konieczne, ale zwykle tylko kilka kilobajtów:

  • headzwykle odczytuje fragmenty po kilka kilobajtów (ponieważ jest to bardziej wydajne niż readwywołanie systemowe dla każdego bajtu - takie zachowanie nazywa się buforowaniem), więc pozostała część ostatniego fragmentu po żądanym ostatnim wierszu jest odrzucana.
  • Przesyłane mogą być pewne dane, ponieważ potoki mają powiązany bufor zarządzany przez jądro (często 512 bajtów). Te dane zostaną odrzucone.
  • grepmogło zgromadzić pewne dane, które są gotowe do przekształcenia się w fragment wyjściowy (ponowne buforowanie). Otrzyma SIGPIPE, gdy będzie próbował opróżnić bufor wyjściowy.

Podsumowując, system jest precyzyjnie zaprojektowany, aby narzędzia filtrujące działały naturalnie wydajnie. Programy, które muszą kontynuować pracę po zaniku kanału wyjściowego, muszą zignorować sygnał SIGPIPE.

Gilles „SO- przestań być zły”
źródło
3

Sortof, potok działa w ten sposób: najpierw wykonuje pierwsze polecenie, a następnie drugie polecenie w twoim przypadku.

Oznacza to, że A|Botrzymamy polecenie. Wtedy nie ma pewności, czy Alub Bzaczyna pierwszy. Mogą rozpocząć się dokładnie w tym samym czasie, jeśli jest wiele procesorów. Potok może przechowywać nieokreśloną, ale skończoną ilość danych.

Jeśli B spróbuje odczytać z potoku, ale żadne dane nie są dostępne, Bpoczeka, aż dane dotrą. Jeśli Bodczytuje z dysku, Bmoże występować ten sam problem i trzeba poczekać, aż odczyt z dysku się zakończy. Dokładniejszą analogią byłoby czytanie z klawiatury. Tam Bmusiałby czekać na wpisanie przez użytkownika. Ale we wszystkich tych przypadkach B rozpoczął operację „odczytu” i musi poczekać, aż zakończy. Ale jeśli Bjest to polecenie, które potrzebuje tylko częściowego wyjścia, Ato po pewnym punkcie, w którym Bosiągnięty jest poziom wejściowyA zostanie zabity przez SIGPIPE

Jeśli Aspróbujesz pisać do potoku, a potok jest pełny, Amusisz poczekać , aż wolne miejsce w potoku stanie się wolne. Amógłby mieć ten sam problem, gdyby zapisywał na terminalu. Terminal ma kontrolę przepływu i może moderować tempo danych. W każdym razie doA , rozpoczął operację „zapisu” i zaczeka na zakończenie operacji zapisu.

Ai Bzachowują się jak koprocesy, chociaż nie wszystkie koprocesy będą komunikować się z potokiem. Żadna z nich nie ma pełnej kontroli nad drugą.

harish.venkat
źródło
1
Pytanie brzmi: „co zrobiłby A, gdy B zamyka bok rury?”
enzotib
2
Czy nie byłby to „zepsuty fajka”?
Patkos Csaba,
1
Jeśli program próbuje odczytywać / zapisywać z / do zamkniętego potoku (np. headWyjścia), w programie pojawia się sygnał SIGPIPE i domyślnym zachowaniem jest wyjście.
Lekensteyn,
Jak dokładnie to odpowiada na pytanie? Wydaje się, że odpowiedź psusi jest krótsza i do rzeczy.
jw013,
1

grepnie ma bezpośredniej kontroli nad potokiem (tylko odbiera dane), a potok nie ma bezpośredniej kontroli nad grep(tylko wysyła dane) ...

To grep, co robi lub jakikolwiek inny program, zależy całkowicie od wewnętrznej logiki tych programów. Jeśli powiesz grepza pomocą opcji wiersza poleceń, aby zrobić wczesne wyjście po znalezieniu , zrobi to, w przeciwnym razie wypali się na samym końcu pliku, szukając wzorca ...

Terminal jest również zupełnie odłączony od wewnętrznych działań grepi shelldziałań związanych z instalowaniem potoków ... Terminal jest w zasadzie tylko polem startowym, a wyświetlacz wyjściowy ...

Peter.O
źródło