Jaka jest różnica między STDIN a argumentami przekazywanymi do polecenia?

16

Mógłbym użyć dowolnego formularza do wykonania catmetody:

cat file_name
cat < file_name

Wynik jest taki sam

Następnie chcę wykonać manw formaciestdin

man < file_name

Chociaż file_namezawiera:

# file_name
cat

Ale wyskakuje What manual page do you want?zamiast wykonać man cat.

Chcę wiedzieć, dlaczego catmożna zaakceptować stdinjako argument, ale mannie mogę. Jaka jest różnica między argumentami wiersza poleceń a stdin?

steveyang
źródło

Odpowiedzi:

21

Twoje pytanie jest ściśle związane z tym, jak używana powłoka analizuje dane wprowadzone przez użytkownika w wierszu poleceń.

Jeśli pierwszym słowem w wierszu poleceń jest program, umieszczony w specjalnym folderze (głównie zdefiniowanym przez PATH) i nie podano już żadnych znaków specjalnych (w zależności od używanej powłoki), wszystkie kolejne słowa oddzielone spacjami lub tabulatorami są przekazywane do program w specjalnej formie, tj. tablica. Z każdym słowem jako jednym elementem w tablicy.

Sposób, w jaki program, który zamierzasz wywołać, interpretuje argumenty (znajdujące się w tablicy) zależy od tego, jak jest programowany. Istnieje kilka quasi-standardów, jak powinna wyglądać składnia argumentów, ale ogólnie programista jest całkowicie darmowy. Zatem pierwszy argument można interpretować jako nazwę pliku lub cokolwiek innego, o czym myśli programista w czasie, gdy pisał program.

W przypadku dodawania znaku specjalnego <lub >do linii poleceń, append shell dosn't <i >ani kolejne słowa do tablicy, która zostanie przekazana do programu. Z <lub >podana powłoka zaczyna wymyślać fantazyjne rzeczy, wspierane przez leżące u jej podstaw jądro (słowa kluczowe piping ). Aby zrozumieć, co się dzieje, musisz zrozumieć, coSTDIN i STDOUT(ponieważ nie jest to bezpośrednio powiązane, pomijam STDERR).

Wszystko, co widzisz na swoim terminalu (w większości przypadków część ekranu) jest zapisywane przez powłokę lub inny program, który wcześniej wywołałeś do specjalnego pliku (w unixie wszystko jest plikiem ). Ten plik ma specjalny identyfikator i nazywa się STDOUT. Jeśli program chce odczytać dane z klawiatury, nie sonduje bezpośrednio klawiatury (przynajmniej w większości przypadków), ale czyta ze specjalnego pliku o nazwie STDIN. Ten plik jest wewnętrznie podłączony do standardowego urządzenia wejściowego, w większości przypadków do klawiatury.

Jeśli powłoka odczytuje <lub >w parsowanym wierszu poleceń, manipuluje STDINlub STDOUTw szczególny sposób na czas działania odpowiedniego programu.STDINi STDOUTnie wskazuje już terminala ani standardowego urządzenia wejściowego, ale raczej kolejną nazwę pliku w wierszu poleceń.

W przypadku dwóch linii

cat file_name
cat < file_name

obserwowane zachowanie jest identyczne, ponieważ odpowiedni programista catalbo odczytuje dane, STDINalbo odczytuje dane z pliku, którego nazwa jest podana jako argument pierwszego wiersza poleceń (który jest pierwszym elementem tablicy przekazywanej przez powłokę cat). Następnie catzapisuje całą zawartość file_namelub STDINdo terminala, ponieważ nie instruujemy powłoki, aby manipulowała STDOUT. Pamiętaj, że w drugim wierszu twoja powłoka manipuluje STDINw ten sposób, aby nie wskazywała na żadne standardowe urządzenie wejściowe, ale wskazuje na plik wywołany file_namew bieżącym katalogu roboczym.

W drugim przypadku linii

man < file_name

mannie ma na celu odczytania niczego, STDINjeśli jest wywoływane bez argumentu, tj. pusta tablica. Więc linia

man < file_name

równa się

man

Na przykład też mancoś odczyta STDIN, jeśli przejdziesz -l -do man. Dzięki tej opcji podanej w wierszu poleceń możesz wyświetlić zawartość dowolnego manodczytu z STDINtwojego terminala. Więc

man -l - < file_name

też by działał (ale bądź ostrożny man to nie tylko pager, ale także analizuje dane wejściowe pliku, więc zawartość pliku i wyświetlana treść mogą się różnić).

Więc jak STDIN,STDOUT a argumenty wiersza polecenia są interpretowane jest wszystko do odpowiedniego dewelopera.

Mam nadzieję, że moja odpowiedź może wyjaśnić.

użytkownik1146332
źródło
Dziękuję za to szczegółowe wyjaśnienie. Dla ostatnich kilku akapitach, wspomniałeś korzystanie man -l - < file_nameaby maninterpretuje STDINjako argumenty, ale to nie w moim systemie z STDERR:man -l - < tee man: invalid option -- l man, version 1.6c
steveyang
Nie ma za co. Ale nie wspomniałem, że przynajmniej moja wersja man( man-db ) odczytuje argumenty STDINz podanymi argumentami, -lpo których następuje -. Po prostu interpretuje dane ze STDINstrony podręcznika. Aby uzyskać bardziej szczegółowe wyjaśnienia poprawnych argumentów i ich interpretacji, należy zajrzeć na stronę podręcznika odpowiedniego programu. W twoim przypadku skonsultuj się man man. Może istnieje podobna opcja dla twojego man. Jeśli chcesz odczytać argumenty wiersza poleceń dla określonego programu z STDIN xargs(jak wspomniano powyżej), jest to droga.
user1146332,
I man manznajduję ten w moim systemie operacyjnym, który go nie obsługuje. W każdym razie dziękuję za tę deklarację tych dwóch koncepcji.
steveyang
Zredagowałem twoją odpowiedź, aby zawierała przydatne linki zamiast lmgtfy. Publikowanie linków lmgtfy jest 1) niegrzeczne, 2) nieprzydatne i 3) naprawdę niezadowolone z witryn SE. Podaj link lub nie, ale jeśli zdecydujesz się to zrobić, podaj link do faktycznych informacji, a nie do sarkastycznego sposobu pokazania komuś, jak je znaleźć.
terdon
12

Oni są zupełnie inni. Argumenty wiersza polecenia są przekazywane do programu w tablicy i może on robić z nimi, co chce; stdin to strumień wejściowy, od którego program musi żądać danych. Programy, które przetwarzają pliki często wybierają obsługę obu, ale muszą to zrobić ręcznie - sprawdzają, czy nazwa pliku została przekazana jako argument wiersza polecenia, a jeśli nie, zamiast tego czytają ze standardowego wejścia

Wygląda na to, że spodziewasz mansię przeczytać standardowe wejście, aby znaleźć stronę podręcznika, którą powinien wyświetlić, co byłoby naprawdę dziwnym zachowaniem; kiedy miałbyś tego użyć? Fakt, że catwyświetla swoje standardowe wejście, jest artefaktem tego, że nie robi nic innego; Nie sądzę, aby inne narzędzie działało w ten sposób. Na przykład grepmoże pobrać nazwę pliku lub odczytać stdin, ale przetwarza dane stdin, nie odczytuje nazwy plikustdin a następnie go nie otwiera

Jeśli naprawdę potrzebujesz takiego zachowania, możesz użyć xargs, który konwertuje plik na argumenty wiersza poleceń:

$ xargs man < file_name

Lub po prostu osadzić catpołączenie w manpołączeniu:

$ man $(cat file_name)
Michał Mrożek
źródło
W bash możesz użyć man $(<file_name).
jordanm
Re: „Nie sądzę, aby inne narzędzie działało w ten sposób” - Perl (<>)w pętli zrobi STDINargumenty wiersza poleceń jako nazwy plików ...
Aaron D. Marasco
@ AaronD.Marasco Miałem na myśli, że żadne narzędzie nie pobiera argumentu ani nie odczytuje nazwy pliku ze standardowego wejścia i odczytuje argument z tego pliku
Michael Mrozek
@MichaelMrozek Dzięki za wyjaśnienie. Celem, który wykorzystałem, man < file_namejest zrozumienie tych dwóch pojęć. Po przeczytaniu wyjaśnienia o implementacji decyduje autor polecenia. Więc jeśli mam rację, findargumenty bierze raczej przetwarza STDIN?
steveyang