Dlaczego powłoka nie naprawia automatycznie „bezużytecznego użycia kota”? [Zamknięte]

28

Wiele osób korzysta z onelinerów i skryptów zawierających kod wzdłuż linii

cat "$MYFILE" | command1 | command2 > "$OUTPUT"

Pierwszy catjest często nazywany „bezużytecznym użyciem kota”, ponieważ technicznie wymaga on rozpoczęcia nowego procesu (często /usr/bin/cat), w którym można by tego uniknąć, gdyby polecenie było

< "$MYFILE" command1 | command2 > "$OUTPUT"

ponieważ wtedy powłoka musi się tylko uruchomić command1i po prostu wskazać stdinna podany plik.

Dlaczego powłoka nie wykonuje tej konwersji automatycznie? Uważam, że składnia „bezużyteczne korzystanie z kota” jest łatwiejsza do odczytania, a powłoka powinna mieć wystarczającą ilość informacji, aby automatycznie pozbyć się bezużytecznego kota. Jest caton zdefiniowany w standardzie POSIX, więc powłoka powinna mieć możliwość implementacji go wewnętrznie zamiast używania ścieżki binarnej. Powłoka może nawet zawierać implementację tylko dla jednej wersji argumentu i wrócić do ścieżki binarnej.

Mikko Rantalainen
źródło
22
Te polecenia nie są tak naprawdę równoważne, ponieważ w jednym przypadku stdin jest plikiem, aw drugim jest potokiem, więc nie byłby to ściśle bezpieczna konwersja. Możesz jednak stworzyć system, który to zrobił.
Michael Homer
14
To, że nie możesz sobie wyobrazić przypadku użycia, nie oznacza, że ​​aplikacja nie może bezużytecznie polegać na określonym zachowaniu. Otrzymanie błędu lseekjest nadal zdefiniowanym zachowaniem i może powodować inny wynik, różne zachowanie blokujące może mieć znaczenie semantyczne itp. Dopuszczalne byłoby dokonanie zmiany, gdybyś wiedział, jakie były inne polecenia i wiedziałeś, że ich to nie obchodzi, lub jeśli po prostu nie dbałeś o kompatybilność na tym poziomie, ale korzyść jest niewielka. Wyobrażam sobie, że brak korzyści napędza sytuację bardziej niż koszt zgodności.
Michael Homer
3
Powłoka absolutnie może się jednak zaimplementować catlub użyć dowolnego innego narzędzia. Dozwolone jest również wiedzieć, jak działają inne narzędzia należące do systemu (np. Może wiedzieć, jak zachowuje się zewnętrzna grepimplementacja dostarczona z systemem ). Jest to całkowicie wykonalne, więc można się zastanawiać, dlaczego tak nie jest.
Michael Homer
6
@MichaelHomer np. Może wiedzieć, jak zachowuje się zewnętrzna implementacja grep dostarczona z systemem, więc powłoka ma teraz zależność od zachowania grep. I sed… I awk… I du… A ile setek, jeśli nie tysiące innych narzędzi?
Andrew Henle,
19
Edycja moich poleceń byłaby dość niewygodna dla mojej powłoki.
Azor Ahai

Odpowiedzi:

25

2 polecenia nie są równoważne: rozważ obsługę błędów:

cat <file that doesn't exist> | less utworzy pusty strumień, który zostanie przekazany do potokowego programu ... jako taki kończy się wyświetleniem niczego.

< <file that doesn't exist> less nie uda się otworzyć paska, a następnie w ogóle się nie otworzy.

Próba zmiany tego pierwszego na drugi może spowodować uszkodzenie dowolnej liczby skryptów, które oczekują uruchomienia programu z potencjalnie pustym wejściem.

UKMonkey
źródło
1
Oznaczę twoją odpowiedź jako przyjętą, ponieważ uważam, że jest to najważniejsza różnica między obiema składniami. Wariant z catzawsze wykona drugie polecenie w potoku, natomiast wariant z samym przekierowaniem wejścia w ogóle nie wykona polecenia, jeśli brakuje pliku wejściowego.
Mikko Rantalainen
Należy jednak pamiętać, że <"missing-file" grep foo | echo 2nie zostanie ono wykonane, grepale zostanie wykonane echo.
Mikko Rantalainen
51

„Bezużyteczne użycie cat” polega raczej na tym, jak piszesz kod, niż na tym, co faktycznie działa po uruchomieniu skryptu. Jest to swego rodzaju anty-wzór projektowy , sposób na osiągnięcie czegoś, co prawdopodobnie można by zrobić w bardziej wydajny sposób. Brak zrozumienia, jak najlepiej połączyć dane narzędzia, aby utworzyć nowe narzędzie. Twierdziłbym, że łączenie kilku sedi / lub awkpoleceń w potoku również czasami można uznać za objaw tego samego anty-wzorca.

Naprawianie przypadków „bezużytecznego użycia cat” w skrypcie jest przede wszystkim kwestią ręcznej naprawy kodu źródłowego skryptu. Narzędzie takie jak ShellCheck może w tym pomóc, wskazując oczywiste przypadki:

$ cat script.sh
#!/bin/sh
cat file | cat
$ shellcheck script.sh

In script.sh line 2:
cat file | cat
    ^-- SC2002: Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead.

Uzyskiwanie powłoki automatycznie do wykonania tego zadania byłoby trudne ze względu na charakter skryptów powłoki. Sposób wykonania skryptu zależy od środowiska odziedziczonego po procesie nadrzędnym oraz od konkretnej implementacji dostępnych poleceń zewnętrznych.

Powłoka niekoniecznie wie, co catjest. Może to być dowolne polecenie z dowolnego miejsca w Twojej $PATHlub funkcja.

Gdyby było to wbudowane polecenie (które może być w niektórych powłokach), miałoby możliwość reorganizacji potoku, tak jak wiedziałby o semantyce wbudowanego catpolecenia. Zanim to zrobi, będzie musiał dodatkowo założyć następne polecenie w potoku, po oryginale cat.

Zauważ, że odczyt ze standardowego wejścia zachowuje się nieco inaczej, gdy jest podłączony do potoku i gdy jest podłączony do pliku. Potok nie jest widoczny, więc w zależności od tego, co zrobi następne polecenie w potoku, może on zachowywać się inaczej, jeśli potok został zmieniony (może wykryć, czy wejście jest widoczne, i zdecydować o zrobieniu różnych rzeczy, jeśli tak jest lub jeśli tak nie jest, w każdym razie zachowałoby się inaczej).

To pytanie jest podobne (w bardzo ogólnym sensie) do „ Czy istnieją jakieś kompilatory, które próbują samodzielnie naprawić błędy składniowe? ” (W witrynie Software Engineering StackExchange), chociaż to pytanie oczywiście dotyczy błędów składniowych, a nie bezużytecznych wzorców projektowych . Pomysł automatycznej zmiany kodu na podstawie intencji jest jednak w dużej mierze taki sam.

Kusalananda
źródło
Powłoka doskonale wie, co catjest, a pozostałe polecenia w potoku (zasada as-if) i zachowują się odpowiednio, po prostu ich tu nie ma, ponieważ jest to bezcelowe i zbyt trudne.
Michael Homer
4
@MichaelHomer Tak. Ale dozwolone jest również przeładowanie standardowego polecenia funkcją o tej samej nazwie.
Kusalananda
2
@PhilipCouling Jest absolutnie zgodny, o ile wiadomo, że nie obchodzi go żadne z poleceń potoku. Powłoka zezwala w szczególności na zastępowanie narzędzi wbudowanymi lub funkcjami powłoki, które nie mają żadnych ograniczeń środowiska wykonawczego, więc dopóki wynik zewnętrzny jest nierozróżnialny, dozwolone. W twoim przypadku cat /dev/ttyjest to interesujący, z którym byłoby inaczej <.
Michael Homer
1
@MichaelHomer , o ile wynik zewnętrzny jest nierozróżnialny, dozwolone, co oznacza, że ​​zachowanie całego zestawu narzędzi zoptymalizowanych w taki sposób nigdy się nie zmieni . To musi być piekło ostatecznej zależności.
Andrew Henle,
3
@MichaelHomer Jak powiedziałem w innych komentarzach, powłoka doskonale wie, że biorąc pod uwagę wkład OP, nie można powiedzieć, co catwłaściwie robi polecenie bez wykonania polecenia . Z tego co wiesz (i powłoka), OP ma na catswojej ścieżce polecenie, które jest interaktywną symulacją kota, „mój plik” jest tylko zapisanym stanem gry command1i command2przetwarza niektóre statystyki dotyczące bieżącej sesji gry ...
alephzero
34

Ponieważ to nie jest bezużyteczne.

W przypadku cat file | cmdfd 0(stdin) cmdbędzie potokiem, aw przypadku cmd <filemoże być zwykłym plikiem, urządzeniem itp.

Potok ma inną semantykę niż zwykły plik, a jego semantyka nie jest podzbiorem semantyki zwykłego pliku:

  • zwykły plik nie może być select(2)edytowany ani poll(2)edytowany w znaczący sposób; a select(2)na nim zawsze zwróci „gotowy”. Zaawansowane interfejsy, takie jak epoll(2)w systemie Linux, po prostu nie będą działać ze zwykłymi plikami.

  • Linux nie ma połączenia systemowe ( splice(2), vmsplice(2), tee(2)), które działają jedynie w rurach [1]

Ponieważ catjest tak często używany, można go zaimplementować jako wbudowaną powłokę, która pozwoli uniknąć dodatkowego procesu, ale kiedy zaczniesz na tej ścieżce, to samo można zrobić z większością poleceń - przekształcając powłokę w wolniejszą i clunkier perllub python. prawdopodobnie lepiej jest napisać inny język skryptowy z łatwą w użyciu składnią przypominającą potok dla kontynuacji ;-)

[1] Jeśli chcesz prosty przykład nie składa się na tę okazję, można spojrzeć na mojego „exec binarny z stdin” git sens z kilku wyjaśnień w komentarzu tutaj . Wdrożenie catw nim, aby działało bez UUoC, uczyniłoby go 2 lub 3 razy większym.

mosvy
źródło
2
W rzeczywistości, ksh93 robi wdrożenia pewnych poleceń zewnętrznych jak catwewnętrznie.
jrw32982 obsługuje Monikę
3
cat /dev/urandom | cpu_bound_programuruchamia read()wywołania systemowe w osobnym procesie. Na przykład w systemie Linux rzeczywista praca procesora polegająca na generowaniu większej liczby liczb losowych (gdy pula jest pusta) odbywa się w tym wywołaniu systemowym, więc użycie osobnego procesu pozwala wykorzystać osobny rdzeń procesora do generowania losowych danych jako danych wejściowych. np. Jaki jest najszybszy sposób na wygenerowanie pliku tekstowego 1 GB zawierającego losowe cyfry?
Peter Cordes
4
Co ważniejsze w większości przypadków oznacza to, że lseeknie będzie działać. cat foo.mp4 | mpv -będzie działać, ale nie możesz szukać dalej niż bufor bufora mpv lub mplayera. Ale z przekierowaniem danych wejściowych z pliku możesz. cat | mpv -to jeden ze sposobów sprawdzenia, czy MP4 ma swój moovatom na początku pliku, więc można go odtwarzać bez szukania do końca i do tyłu (tj. czy nadaje się do przesyłania strumieniowego). Łatwo jest wyobrazić sobie inne przypadki, w których chcesz przetestować program pod kątem niewidzialnych plików, uruchamiając go /dev/stdinz catprzekierowaniem.
Peter Cordes
Jest to jeszcze bardziej prawdziwe podczas korzystania xargs cat | somecmd. Jeśli ścieżki plików wykraczają poza limit bufora poleceń, xargsmogą być uruchamiane catwiele razy, co powoduje ciągły strumień, a xargs somecmdbezpośrednie użycie często kończy się niepowodzeniem, ponieważ somecmdnie można uruchomić ich w wielu miejscach, aby uzyskać płynny wynik.
plandeka
17

Ponieważ wykrycie bezużytecznego kota jest naprawdę bardzo trudne.

Miałem skrypt powłoki, w którym pisałem

cat | (somecommand <<!
...
/proc/self/fd/3
...
!) 0<&3

Skrypt powłoki nie powiódł się w produkcji, jeśli catzostał usunięty, ponieważ został wywołany przez su -c 'script.sh' someuser. Pozornie zbędne catspowodowało, że właściciel standardowego wejścia zmienił się na użytkownika, który działał skrypt, tak że ponowne otwarcie go /procdziałało.

Jozuego
źródło
Ten przypadek byłby dość łatwy, ponieważ wyraźnie nie jest zgodny z prostym modelem, catpo którym następuje dokładnie jeden parametr, więc powłoka powinna używać prawdziwego catpliku wykonywalnego zamiast zoptymalizowanego skrótu. Warto jednak zwrócić uwagę na możliwe inne dane uwierzytelniające lub niestandardowe standardowe wejście dla rzeczywistych procesów.
Mikko Rantalainen
13

tl; dr: Pociski nie robią tego automatycznie, ponieważ koszty przekraczają prawdopodobne korzyści.

Inne odpowiedzi wskazywały na różnicę techniczną między stdin będącym potokiem a byciem plikiem. Mając to na uwadze, powłoka może wykonać jedną z następujących czynności:

  1. Wdrożenie catjako wbudowane, nadal zachowując rozróżnienie pliku v. Potoku. Pozwoliłoby to zaoszczędzić koszty egzekucji i być może rozwidlenia.
  2. Wykonaj pełną analizę potoku ze znajomością różnych poleceń używanych do sprawdzenia, czy plik / potok ma znaczenie, a następnie działaj na jego podstawie.

Następnie musisz wziąć pod uwagę koszty i korzyści każdego podejścia. Korzyści są dość proste:

  1. W obu przypadkach unikaj exec (z cat)
  2. W drugim przypadku, gdy możliwe jest zastąpienie przekierowania, unikanie rozwidlenia.
  3. W przypadkach, w których trzeba użyć rury, to może być możliwe, aby uniknąć czasami widelca / vfork, ale często nie. Jest tak, ponieważ ekwiwalent kota musi działać w tym samym czasie co reszta rurociągu.

Dzięki temu oszczędzasz trochę czasu procesora i pamięci, zwłaszcza jeśli możesz uniknąć rozwidlenia. Oczywiście oszczędzasz ten czas i pamięć tylko wtedy, gdy funkcja jest rzeczywiście używana. I tak naprawdę oszczędzasz tylko czas na rozwidlenie / wykonanie; w przypadku większych plików czas to głównie czas operacji we / wy (tzn. kot czyta plik z dysku). Musisz więc zapytać: jak często jest catużywany (bezużytecznie) w skryptach powłoki, w których wydajność ma znaczenie? Porównaj go z innymi popularnymi wbudowanymi powłokami, takimi jak test- trudno sobie wyobrazić, że catjest używany (bezużytecznie) nawet z jedną dziesiątą tak często, jak testw miejscach, które mają znaczenie. Zgaduję, że nie zmierzyłem, co chciałbyś zrobić przed każdą próbą wdrożenia. (Lub podobnie, prosząc kogoś innego o wdrożenie np. Żądania funkcji).

Następnie pytasz: jakie są koszty. Dwa koszty, które przychodzą na myśl, to (a) dodatkowy kod w powłoce, który zwiększa jej rozmiar (a tym samym możliwe użycie pamięci), wymaga więcej prac konserwacyjnych, jest kolejnym miejscem na błędy itp .; oraz (b) zaskakuje kompatybilność wsteczna, POSIX catpomija wiele funkcji np. GNU coreutils cat, więc musisz uważać dokładnie, co catwbudowałoby.

  1. Dodatkowa wbudowana opcja prawdopodobnie nie jest taka zła - dodanie jeszcze jednego wbudowanego, w którym już istnieje kilka. Gdybyś miał dane profilujące, które by to pomogły, prawdopodobnie możesz przekonać autorów ulubionej powłoki, aby je dodali.

  2. Jeśli chodzi o analizę potoku, nie sądzę, aby powłoki robiły obecnie coś takiego (kilka rozpoznaje koniec potoku i może uniknąć rozwidlenia). Zasadniczo dodajesz do powłoki (prymitywny) optymalizator; Optymalizatory często okazują się skomplikowanym kodem i źródłem wielu błędów. Te błędy mogą być zaskakujące - niewielkie zmiany w skrypcie powłoki mogą zakończyć się uniknięciem lub wywołaniem błędu.

Postscript: Możesz zastosować podobną analizę do swoich bezużytecznych zastosowań kota. Korzyści: łatwiejszy do odczytania (chociaż jeśli polecenie1 weźmie plik jako argument, prawdopodobnie nie). Koszty: dodatkowe rozwidlenie i exec (a jeśli polecenie1 może przyjąć plik jako argument, prawdopodobnie bardziej mylące komunikaty o błędach). Jeśli z analizy wynika, że ​​bezużytecznie używasz kota, to śmiało.

derobert
źródło
10

catKomenda może zaakceptować -jako marker stdin . ( POSIX , „ Jeśli plik ma wartość„ - ”, narzędzie cat odczytuje ze standardowego wejścia w tym punkcie sekwencji. ”) Pozwala to na prostą obsługę pliku lub standardowego wejścia, w przeciwnym razie byłoby to niedozwolone.

Rozważ te dwie trywialne alternatywy, w których argumentem powłoki $1jest -:

cat "$1" | nl    # Works completely transparently
nl < "$1"        # Fails with 'bash: -: No such file or directory'

Kolejny czas catjest przydatny, gdy jest celowo używany jako brak operacji w celu utrzymania składni powłoki:

file="$1"
reader=cat
[[ $file =~ \.gz$ ]] && reader=zcat
[[ $file =~ \.bz2$ ]] && reader=bzcat
"$reader" "$file"

Wreszcie, uważam, że jedyny raz, kiedy UUOC można naprawdę poprawnie wywołać, jest catużycie nazwy pliku, która jest znana jako zwykły plik (tj. Nie jest urządzeniem ani nazwaną potokiem) i że komenda nie otrzymuje żadnych flag:

cat file.txt

W każdej innej sytuacji catmogą być wymagane same właściwości .

roaima
źródło
6

Polecenie cat może robić rzeczy, których muszla niekoniecznie musi robić (a przynajmniej nie może robić łatwo). Załóżmy na przykład, że chcesz wydrukować znaki, które w innym przypadku byłyby niewidoczne, takie jak tabulatory, znaki powrotu karetki lub znaki nowej linii. * Może * być na to sposób, używając tylko poleceń wbudowanych w powłokę, ale nie mogę wymyślić żadnego z góry. Wersja cat GNU może to robić za pomocą -Aargumentów lub -v -E -Targumentów (chociaż nie wiem o innych wersjach cat). Możesz również poprzedzić każdą linię numerem linii za pomocą -n(ponownie IDK, jeśli wersje inne niż GNU mogą to zrobić).

Kolejną zaletą cat jest to, że może on z łatwością czytać wiele plików. Aby to zrobić, wystarczy wpisać cat file1 file2 file3. Aby zrobić to samo z powłoką, sytuacja stałaby się trudna, chociaż starannie wykonana pętla najprawdopodobniej mogłaby osiągnąć ten sam wynik. To powiedziawszy, czy naprawdę chcesz poświęcić czas na napisanie takiej pętli, skoro istnieje taka prosta alternatywa? Ja nie!

Czytanie plików za pomocą cat prawdopodobnie zużyłoby mniej procesora niż powłoka, ponieważ cat jest programem wstępnie skompilowanym (oczywistym wyjątkiem jest każda powłoka, która ma wbudowanego cat). Podczas czytania dużej grupy plików może to stać się oczywiste, ale nigdy tego nie zrobiłem na moich komputerach, więc nie mogę być tego pewien.

Polecenie cat może być również przydatne do zmuszania polecenia do zaakceptowania standardowego wejścia w przypadkach, w których może nie być. Rozważ następujące:

echo 8 | sleep

Liczba „8” nie zostanie zaakceptowana przez polecenie „uśpienia”, ponieważ tak naprawdę nigdy nie była przeznaczona do przyjęcia standardowego wejścia. Zatem sen zlekceważy te dane, narzeka na brak argumentów i wychodzi. Jednak jeśli jeden typ:

echo 8 | sleep $(cat)

Wiele pocisków rozwinie to do sleep 8i sen będzie czekał 8 sekund przed wyjściem. Możesz także zrobić coś podobnego z ssh:

command | ssh 1.2.3.4 'cat >> example-file'

To polecenie z dołączonym plikiem przykładowym na komputerze o adresie 1.2.3.4 z dowolnym wyjściem z „polecenia”.

I to (prawdopodobnie) po prostu drapie powierzchnię. Jestem pewien, że mógłbym znaleźć więcej przykładów przydatności kota, gdybym chciał, ale ten post jest wystarczająco długi. Podsumowując, powiem tak: proszenie powłoki o przewidywanie wszystkich tych scenariuszy (i kilku innych) jest naprawdę niewykonalne.

TSJNachos117
źródło
Kończę
3

Pamiętaj, że użytkownik może mieć catw swoim $PATHktóra nie jest dokładnie POSIX cat(ale być może jakiś wariant, który mógłby coś gdzieś zalogować). W takim przypadku nie chcesz, aby powłoka go usunęła.

PATH Może zmienić się dynamicznie, a następnie cat nie jest to, co uważam, że jest. Trudno byłoby napisać powłokę wykonującą optymalizację, o jakiej marzysz.

Ponadto w praktyce cat jest to dość szybki program. Jest kilka praktycznych powodów (oprócz estetyki), aby tego uniknąć.

Zobacz także doskonałe przemówienie Piekła na temat POSIX [Y] Regina-Gianasa na FOSDEM2018. Daje to inne powody, aby unikać robienia tego, o czym marzysz w skorupce.

Gdyby wydajność była naprawdę problemem dla powłok, ktoś zaproponowałby powłokę, która wykorzystuje wyrafinowaną optymalizację kompilatora całego programu, statyczną analizę kodu źródłowego i techniki kompilacji just-in-time (wszystkie te trzy domeny mają dziesięciolecia postępu oraz publikacje naukowe i dedykowane konferencje, np. w ramach SIGPLAN ). Niestety, nawet jako interesujący temat badawczy, który nie jest obecnie finansowany przez agencje badawcze lub inwestorów venture capital, i dedukuję, że po prostu nie jest to warte wysiłku. Innymi słowy, prawdopodobnie nie ma znaczącego rynku na optymalizację pocisków . Jeśli masz pół miliona euro na takie badania, łatwo znajdziesz kogoś, kto to zrobi, i wierzę, że przyniosłoby to wartościowe wyniki.

Z praktycznego punktu widzenia, przepisywania, w celu poprawy wydajności, często wykonuje się mały (sto wierszy) skrypt powłoki w dowolnym lepszym języku skryptowym (Python, AWK, Guile, ...). I nie jest rozsądne (z wielu powodów inżynierii oprogramowania) pisanie dużych skryptów powłoki: gdy piszesz skrypt powłoki przekraczający sto wierszy, musisz rozważyć jego przepisanie (nawet ze względu na czytelność i konserwację) w bardziej odpowiednim języku : jako język programowania powłoka jest bardzo słaba. Istnieje jednak wiele generowanych skryptów powłoki i nie bez powodu (np. configureSkrypty generowane przez autoconf GNU ).

Jeśli chodzi o ogromne pliki tekstowe, przekazywanie ich catjako pojedynczego argumentu nie jest dobrą praktyką, a większość sysadminów wie o tym (gdy uruchomienie dowolnego skryptu powłoki zajmuje więcej niż minutę, zaczynasz rozważać jego optymalizację). W przypadku dużych plików gigabajtów nigdy niecat jest dobrym narzędziem do ich przetwarzania.

Basile Starynkevitch
źródło
3
„Sporo praktycznych powodów, aby tego uniknąć” - każdy, kto czekał na cat some-huge-log | tail -n 5bieg (gdzie tail -n 5 some-huge-logmógłby skoczyć prosto do końca, podczas gdy catczyta tylko od przodu do tyłu) nie zgodziłby się.
Charles Duffy
Komentowanie catdużego pliku tekstowego w zakresie kilkudziesięciu GB (który został stworzony do testowania) zajmuje trochę czasu. Nie poleciłbym.
Sergiy Kolodyazhnyy
1
BTW, re: „brak znaczącego rynku na optymalizowanie powłok” - ksh93 to optymalizująca powłoka i całkiem niezła. To było przez jakiś czas, z powodzeniem sprzedawane jako produkt handlowy. (Niestety, posiadanie licencji komercyjnej sprawiło, że była wystarczająco niszowa, że ​​słabo napisane klony i inni mniej zdolni, ale wolni od kosztów następcy przejęli świat poza tymi stronami, które chcą zapłacić za licencję, co prowadzi do sytuacji, w której mam dzisiaj).
Charles Duffy
(nie używając określonych technik, które zauważasz, ale szczerze mówiąc, techniki te nie mają sensu, biorąc pod uwagę model procesu; techniki, które stosuje, są dobrze zastosowane i dają dobry efekt ).
Charles Duffy
2

Dodając do odpowiedzi @Kusalananda (i komentarza @alephzero), cat może być dowolny:

alias cat='gcc -c'
cat "$MYFILE" | command1 | command2 > "$OUTPUT"

lub

echo 'echo 1' > /usr/bin/cat
cat "$MYFILE" | command1 | command2 > "$OUTPUT"

Nie ma powodu, dla którego cat (sam) lub / usr / bin / cat w systemie faktycznie jest narzędziem cat konkatenate.

Obrabować
źródło
3
Inne niż zachowanie catjest zdefiniowane przez POSIX i dlatego nie powinno być zupełnie inne.
roaima
2
@roaima: PATH=/home/Joshua/bin:$PATH cat ...Czy na pewno wiesz, co catteraz?
Joshua
1
@Joshua, to naprawdę nie ma znaczenia. Oboje wiemy, że catmożna to zmienić, ale oboje wiemy, że nie należy bezmyślnie zastępować go czymś innym. W moim komentarzu wskazano, że POSIX nakazuje określone (podzbiór) zachowanie, które można zasadnie oczekiwać. Czasami napisałem skrypt powłoki, który rozszerza działanie standardowego narzędzia. W tym przypadku skrypt powłoki zachowywał się i zachowywał tak jak narzędzie, które zastąpił, z tym wyjątkiem, że miał dodatkowe możliwości.
roaima
@Joshua: Na większości platform powłoki wiedzą (lub mogłyby wiedzieć), które katalogi przechowują pliki wykonywalne, które implementują polecenia POSIX. Możesz więc po prostu odroczyć podstawienie do momentu rozwinięcia aliasu i rozpoznania ścieżki i zrobić to tylko dla /bin/cat. (I uczyniłbyś to opcją, którą możesz wyłączyć.) Lub zrobiłbyś catwbudowaną powłokę (do której może się /bin/catprzydać wiele argumentów?), Aby użytkownicy mogli kontrolować, czy chcą, aby wersja zewnętrzna była normalna sposób, z enable cat. Jak dla kill. (Myślałem, że bash command catzadziała, ale to nie pomija wbudowanych)
Peter Cordes
Jeśli podasz alias, powłoka będzie wiedziała, że catw tym środowisku nie odnosi się już do zwykłego cat. Oczywiście optymalizację należy wdrożyć po przetworzeniu aliasów. Uważam, że wbudowane powłoki reprezentują polecenia w katalogu wirtualnym, który zawsze jest poprzedzony twoją ścieżką. Jeśli chcesz uniknąć wbudowanej w powłokę wersji dowolnego polecenia (np. test), Musisz użyć wariantu ze ścieżką.
Mikko Rantalainen
1

Dwa „bezużyteczne” zastosowania dla kota:

sort file.txt | cat header.txt - footer.txt | less

... tutaj catsłuży do miksowania danych wejściowych pliku i potoku.

find . -name '*.info' -type f | sh -c 'xargs cat' | sort

... tutaj xargsmożesz zaakceptować praktycznie nieskończoną liczbę nazw plików i uruchomić cattyle razy, ile potrzeba, jednocześnie zachowując się jak jeden strumień. Działa to więc w przypadku dużych list plików, w przypadku których bezpośrednie użycie xargs sortnie.

uszczelka
źródło
Oba te przypadki użycia można by w trywialny sposób uniknąć, wprowadzając powłokę tylko w kroku, jeśli catwywoływana jest z dokładnie jednym argumentem. Zwłaszcza w przypadku, gdy shprzekazany jest ciąg znaków i xargszadzwoni catbezpośrednio, nie ma możliwości, aby powłoka mogła użyć wbudowanej implementacji.
Mikko Rantalainen
0

Oprócz innych rzeczy, cat-check spowodowałoby dodatkowe obciążenie wydajności i zamieszanie co do tego, które użycie catjest faktycznie bezużyteczne, IMHO, ponieważ takie kontrole mogą być nieefektywne i powodować problemy z legalnym catużyciem.

Gdy komendy dotyczą standardowych strumieni, muszą tylko dbać o odczyt / zapis do standardowych deskryptorów plików. Polecenia mogą wiedzieć, czy standardowe wejście można zobaczyć / zobaczyć, czy nie, co wskazuje na potok lub plik.

Jeśli dodamy do miksu sprawdzanie, jaki proces faktycznie zapewnia tę zawartość standardową, będziemy musieli znaleźć proces po drugiej stronie potoku i zastosować odpowiednią optymalizację. Można to zrobić pod względem samej powłoki, jak pokazano w poście SuperUser autorstwa Kyle'a Jonesa, oraz pod względem powłoki, która

(find /proc -type l | xargs ls -l | fgrep 'pipe:[20043922]') 2>/dev/null

jak pokazano w połączonym poście. To jeszcze 3 polecenia (tak dodatkowe fork()s i exec()s) i rekurencyjne przejścia (tak dużo readdir()połączeń).

Jeśli chodzi o C i kod źródłowy powłoki, powłoka zna już proces potomny, więc nie ma potrzeby rekurencji, ale skąd wiemy, kiedy zoptymalizować, a kiedy w catrzeczywistości jest bezużyteczny? W rzeczywistości istnieją użyteczne zastosowania kota , takie jak

# adding header and footer to file
( cmd; cat file; cmd ) | cmd
# tr command does not accept files as arguments
cat log1 log2 log3 | tr '[:upper:]' '[:lower:]'

Dodanie takiej optymalizacji do powłoki byłoby prawdopodobnie marnotrawstwem i niepotrzebnym narzutem. Jak już wspomniano w odpowiedzi Kusalandy, w UUOC chodzi raczej o to, że użytkownik nie rozumie, jak najlepiej łączyć polecenia, aby uzyskać najlepsze wyniki.

Sergiy Kolodyazhnyy
źródło