Wiele narzędzi wiersza polecenia może pobierać dane wejściowe z potoku lub jako argument nazwy pliku. W przypadku skryptów o długiej powłoce rozpoczęcie łańcucha od znaku cat
sprawia, że jest on bardziej czytelny, zwłaszcza jeśli pierwsze polecenie wymaga wieloliniowych argumentów.
Porównać
sed s/bla/blaha/ data \
| grep blah \
| grep -n babla
i
cat data \
| sed s/bla/blaha/ \
| grep blah \
| grep -n babla
Czy ta ostatnia metoda jest mniej wydajna? Jeśli tak, czy różnica jest wystarczająca, aby się martwić, czy skrypt zostanie uruchomiony, powiedzmy, raz na sekundę? Różnica w czytelności nie jest ogromna.
shell-script
performance
pipe
cat
tshepang
źródło
źródło
cat
. Myślę jednak, że większym pytaniem jest tutaj czytelność kodu, który często ma pierwszeństwo przed wydajnością. Skoro szybciej można pisać ładniej , dlaczego nie? Wskazanie problemucat
zwykle prowadzi do lepszego zrozumienia przez użytkownika rurociągów i procesów. Warto spróbować, więc następnym razem piszą zrozumiały kod.cat
; punkt Caleba na temat używania funkcji i przekierowywania również to rozwiązuje.)Odpowiedzi:
„Ostateczna” odpowiedź jest oczywiście dostarczana przez The Useless Use of
cat
Award .Utworzenie instancji cat tylko po to, by Twój kod odczytywał inaczej, zapewnia jeszcze jeden proces i jeszcze jeden zestaw strumieni wejściowych / wyjściowych, które nie są potrzebne. Zazwyczaj prawdziwym problemem w skryptach będą nieefektywne pętle i przetwarzanie. W większości nowoczesnych systemów jeden dodatkowy
cat
nie zabije twojej wydajności, aleprawiezawsze istnieje inny sposób na napisanie kodu.Jak zauważyłeś, większość programów jest w stanie zaakceptować argument dla pliku wejściowego. Jednak zawsze istnieje wbudowana powłoka,
<
której można użyć wszędzie tam, gdzie oczekuje się strumienia STDIN, co pozwoli ci zaoszczędzić jeden proces, wykonując pracę w już uruchomionym procesie powłoki.Możesz nawet wykazać się kreatywnością GDZIE to piszesz. Zwykle byłby umieszczony na końcu polecenia przed określeniem przekierowań wyjściowych lub potoków takich jak to:
Ale nie musi tak być. Może nawet być na pierwszym miejscu. Na przykład twój przykładowy kod może być napisany w następujący sposób:
Jeśli zależy Ci na czytelności skryptu, a kod jest na tyle bałaganiarski, że dodanie wiersza dla
cat
ma ułatwić śledzenie, istnieją inne sposoby wyczyszczenia kodu. Jednym z nich, z którego często korzystam, co ułatwia późniejsze rozpoznawanie skryptów, jest dzielenie potoków na logiczne zestawy i zapisywanie ich w funkcjach. Kod skryptu staje się wtedy bardzo naturalny, a każda część potoku jest łatwiejsza do debugowania.Następnie możesz kontynuować
fix_blahs < data | fix_frogs | reorder | format_for_sql
. Ścieżka, która tak czyta, jest naprawdę łatwa do naśladowania, a poszczególne komponenty można łatwo debugować w odpowiednich funkcjach.źródło
<file
może nastąpić przed rozkazem. To rozwiązuje wszystkie moje problemy!<file
może przyjść w dowolnym miejscu wiersza poleceń:<file grep needle
lubgrep <file needle
lubgrep needle <file
. Wyjątkiem są złożone polecenia, takie jak pętle i grupowanie; tam przekierowanie musi nastąpić po zamknięciudone
/}
/)
/ itp. @Caleb Dotyczy to wszystkich powłok Bourne / POSIX. I nie zgadzam się, że to brzydkie.$(cat /some/file)
z$(< /some/file)
, który robi to samo, ale unika tarła proces.$(< /some/file)
ma ograniczoną przenośność. Działa w trybie bash, ale nie na przykład popiołu BusyBox lub sh FreeBSD. Prawdopodobnie też nie działa w desce rozdzielczej, ponieważ te trzy ostatnie muszle są bliskimi kuzynami.Oto podsumowanie niektórych wad:
koniec
$file
powyżej. W przypadkucat
jest to zawsze problem, z wyjątkiemzsh
; w przypadku przekierowania jest to tylko problem dlabash
lub,ksh88
a dla niektórych innych powłok tylko w trybie interaktywnym (nie w skryptach).cmd
jest wbudowany, to nawet 2 procesy w niektórych powłokach, takich jakbash
.cat
jest wbudowany, że wykonywane jest także dodatkowe polecenie (i oczywiście ładowane i inicjowane (oraz biblioteki, z którymi jest powiązany)).cat
icmd
procesów oraz stale napełnić i opróżnić bufor rury. Nawet jeślicmd
robi1GB
dużyread()
układ połączeń na raz, kontrola będzie musiał przejść tam iz powrotem pomiędzycat
acmd
ponieważ rura nie może posiadać więcej niż kilka kilobajtów danych na raz.cmd
(jakwc -c
) mogą dokonać optymalizacji, gdy ich standardowe wejście jest zwykłym plikiem, z którym nie mogącat | cmd
sobie poradzić, ponieważ ich standardowe wejście jest wtedy tylko potokiem. Za pomocącat
i potoku oznacza to również, że nie mogą oneseek()
znajdować się w pliku. W przypadku poleceń takich jaktac
lubtail
, ma to ogromną różnicę w wydajności, ponieważ oznacza to, że wraz zcat
nimi muszą przechowywać całe dane wejściowe w pamięci.cat $file
, A nawet jego bardziej poprawna wersjacat -- "$file"
nie będzie działać prawidłowo w przypadku niektórych określonych nazw plików, takich jak-
(lub--help
czy cokolwiek zaczynając-
przypadku zapomnienia--
). Jeśli ktoś nalega na użyciecat
, prawdopodobnie powiniencat < "$file" | cmd
zamiast tego użyć niezawodności.$file
nie można go otworzyć do odczytu (odmowa dostępu, nie istnieje ...),< "$file" cmd
zgłosi spójny komunikat o błędzie (przez powłokę) i nie uruchomi sięcmd
, podczas gdycat $file | cmd
nadal będzie działać,cmd
ale ze standardowym stdin wygląda jak pusty plik. Oznacza to również, że w takie rzeczy< file cmd > file2
,file2
nie jest niszczona, jeślifile
nie można otworzyć.źródło
truncate -s10G a; time wc -c < a; time cat a | wc -c; time cat a | cat | wc -c
. Obraz zawiera wiele parametrów. Kara za wyniki może wynosić od 0 do 100%. W każdym razie nie sądzę, że kara może być ujemna.wc -c
jest dość wyjątkowym przypadkiem, ponieważ ma skrót. Jeśli zrobiszwc -w
to, jest to porównywalne zgrep
moim przykładem (tj. Bardzo małe przetwarzanie - w takiej sytuacji „<” może mieć znaczenie).wc -w
na rzadkim pliku 1 GB w lokalizacji C na Linuksie 4.9 amd64), to okazuje się, że podejście cat zajmuje 23% więcej czasu w systemie wielordzeniowym i 5% podczas wiązania ich z jednym rdzeniem. Pokazuje dodatkowe koszty związane z dostępem do danych przez więcej niż jeden rdzeń. Prawdopodobnie uzyskasz różne wyniki, jeśli zmienisz rozmiar potoku, użyjesz różnych danych, zaangażujesz prawdziwe operacje we / wy, użyje implementacji cat używającej splice () ... Wszystko to potwierdza, że na zdjęciu pojawia się wiele parametrów i to w żadnym wypadkucat
nie pomoże.wc -w
różnica wynosi około 2% ... 15% różnicy, jeśli jest to prosty prosty grep. Co dziwne, jeśli jest w udziale plików NFS, to jest o 20% szybszy do odczytania, jeśli jest przesyłany strumieniowocat
( gist.github.com/rdp/7162414833becbee5919cda855f1cb86 ) Dziwne ...Umieszczenie
<file
na końcu potoku jest mniej czytelne niżcat file
na początku. Naturalny angielski czyta od lewej do prawej.Umieszczenie
<file
A początek rurociągu jest mniej czytelny niż kot, powiedziałbym. Słowo jest bardziej czytelne niż symbol, zwłaszcza symbol, który wydaje się wskazywać w niewłaściwy sposób.Użycie
cat
zachowujecommand | command | command
format.źródło
<
raz powoduje, że kod staje się mniej czytelny, ponieważ niszczy spójność składni multipipeline.<
podobny do tego:alias load='<'
a następnie użyj npload file | sed ...
. Aliasów można używać w skryptach po uruchomieniushopt -s expand_aliases
.Jedną z rzeczy, na które inne odpowiedzi tutaj nie wydają się bezpośrednio dotyczyć, jest to, że
cat
takie użycie nie jest „bezużyteczne” w tym sensie, że „pojawia się zewnętrzny proces kota, który nie działa”; jest bezużyteczny w tym sensie, że „spawnowany jest proces kota, który wykonuje tylko niepotrzebną pracę”.W przypadku tych dwóch:
powłoka uruchamia proces sed, który odczytuje odpowiednio z pliku tymczasowego lub standardowego, a następnie wykonuje pewne przetwarzanie - odczytuje, dopóki nie trafi do nowej linii, zastępuje pierwsze „foo” (jeśli istnieje) w tym wierszu „paskiem”, a następnie drukuje tę linię na standardowe wyjście i pętle.
W przypadku:
Powłoka spawnuje proces kota i proces sed, a przewody stdout kota łączą ze stdin sed. Proces cat odczytuje z pliku kilka kilogramów, a może mega-bajtów, a następnie zapisuje je na standardowym wyjściu, gdzie sommand sed odbiera stamtąd, jak w drugim przykładzie powyżej. Podczas gdy sed przetwarza ten fragment, kot czyta inny fragment i zapisuje go w swoim standardzie, aby sed mógł dalej pracować.
Innymi słowy, dodatkowa praca wymagana przez dodanie
cat
polecenia to nie tylko dodatkowa praca polegająca na spawnowaniu dodatkowegocat
procesu, ale także dodatkowa praca polegająca na odczytywaniu i zapisywaniu bajtów pliku dwa razy zamiast raz. Teraz, praktycznie rzecz biorąc i na nowoczesnych systemach, nie robi to wielkiej różnicy - może sprawić, że twój system wykona kilka mikrosekund niepotrzebnej pracy. Ale jeśli chodzi o skrypt, który planujesz rozpowszechnić, potencjalnie dla osób używających go na komputerach, które są już słabo zasilane, kilka mikrosekund może zsumować się z wieloma iteracjami.źródło
cat
.cat
podzielone przez ms bezcat
procentowo (np. 264 ms / 216 ms = 1,22 = 122% = 22% wolniej zcat
)