2009-10-01 12 views
6

Rozważmy:rurowe, standardowe wejście i wiersza poleceń argumenty Bash

command1 | command2 

jest wyjście komendzie command1 wykorzystane jako standardowe wejście command2 lub jako argumentów wiersza poleceń do polecenie2?

Przykładowo

cat test.sh | grep "hehe" 

co jest jego odpowiednikiem formy bez użycia rur?

Próbowałem

grep "hehe" $(cat test.sh) 

i wydaje się nie być prawidłowe.

+1

Twoje pytanie jest trochę mylące - mam nadzieję, że albo przekierowanie wejścia lub po prostu podanie nazwy pliku jako argumentu jest tym, co chciałeś. Z drugiej strony, jeśli pytasz, jak wziąć stdout jednego polecenia i przekazać go do stdin innego polecenia bez użycia potoku ... to jest definicja potoku. – Cascabel

Odpowiedz

14
grep "hehe" < test.sh 

przekierowanie wejścia - działa tylko na jednym pliku, oczywiście, natomiast cat prac dla dowolnej liczby plików wejściowych.


Rozważmy postaciach:

grep "hehe" $(cat test.sh) 
grep "hehe" `cat test.sh` 

te odpowiadają w tej dziedzinie; dużo łatwiej jest używać „$(cmd)” notacji w zagnieżdżonych zastosowań, takich jak:

x=$(dirname $(dirname $(which gcc))) 
x=`dirname \`dirname \\\`which gcc\\\`\`` 

(Daje to podstawowy katalog, w którym zainstalowany jest GCC, w przypadku, gdy zastanawiasz.)

W Przykładowo, co się dzieje, jest to, że treść test.sh jest odczytywana i dzielona na słowa oddzielone białymi znakami, a każde takie słowo jest dostarczane jako argument do grep. Od grep traktuje słowa po "hehe" (gdzie grep, oczywiście, nie , nie zobacz podwójne cudzysłowy - i nie są one potrzebne w tym przypadku, z reguły używać pojedynczych cudzysłowów, a nie podwójnych cudzysłowów, zwłaszcza wokół skomplikowanych ciągów takich jak wyrażenia regularne, które często używają metaznaków powłoki) ... Jak już mówiłem, grep traktuje słowa po "hehe" jako nazwy plików i próbuje otworzyć każdy plik, zwykle nie działa zawrotnie, ponieważ pliki nie istnieją. Dlatego notacja nie jest odpowiednia w tym kontekście.

Po ponownej analizie pytania można powiedzieć jeszcze więcej - o czym jeszcze nie powiedziano.

Po pierwsze, wiele poleceń Uniksa zaprojektowano tak, aby działały jako "filtry"; odczytują dane wejściowe z niektórych plików, przekształcają je w pewien sposób i zapisują wynik na standardowe wyjście. Takie polecenia są przeznaczone do użycia w obrębie potoków poleceń. Przykłady obejmują:

  • kot
  • grep
  • troff i krewni
  • awk (z zastrzeżeniami)
  • sed
  • rodzaj

Wszystkie te filtry mają taką samą ogólną zachowanie : pobierają opcje wiersza poleceń, aby kontrolować swoje zachowanie, a następnie albo odczytują plik s podane jako argumenty linii poleceń lub, jeśli nie ma takich argumentów, odczytują ich standardowe wejście. Niektóre (np. sort) mogą mieć opcje kontrolowania, gdzie ich wyjście idzie zamiast standardowego wyjścia, ale jest to stosunkowo rzadkie.

Istnieje kilka czystych filtrów - tr jest jednym z takich, który ściśle czyta standardowe wejście i zapisuje na standardowe wyjście.

Inne polecenia mają różne zachowania. Eric Raymond zapewnia taksonomię dla typów poleceń w "The Art of UNIX Programming".

Niektóre polecenia generują listy nazw plików na standardowe wyjście - dwie klasyki to ls i find.

Czasami należy zastosować wyjście z generatora nazw plików jako argumentów wiersza poleceń dla filtru. Jest program, który robi to automatycznie - jest to xargs.

Klasycznie, użyłbyś:

find . -name '*.[chyl]' | xargs grep -n magic_name /dev/null 

będzie to generować kompletną listę plików z '.c', '.h', '.y' i '.l' (źródło C, nagłówki rozszerzeń, Yacc i pliki Lex). Gdy lista zostanie odczytana przez xargs, utworzy wiersze poleceń z grep -n magic_name /dev/null na początku i każde słowo (oddzielone białą spacją) jako argument.

W dawnych czasach nazwy plików uniksowych nie zawierały spacji. Pod wpływem komputerów Mac i Windows takie przestrzenie są teraz powszechne. Wersje GNU find i xargs mają komplementarne możliwości radzenia sobie z tym problemem:

find . -name '*.[chyl]' -print0 | xargs -0 grep -n magic_name /dev/null 

Opcja „-print0” oznacza „nazwy plików drukowania zakończona NUL«\ 0»” (bo tylko znaki, które nie mogą pojawić się w (prostej) nazwie pliku są "/" i NUL, i oczywiście "/" może pojawić się w nazwach ścieżek). Odpowiedni "-0" mówi, aby wyszukać nazwy zakończone przez NUL zamiast nazw rozdzielanych spacjami.

+0

Czy przekierowanie wejścia zapewnia wejście stdin lub argument wiersza poleceń do grep? – Tim

+0

Właściwie moje pytanie jest bardziej ogólne niż grep. – Tim

+0

Więc widzę, po oczyszczeniu ... i uogólniłem moją odpowiedź: D –

1

Jest używany jako stdin.

Spróbuj:

grep "hehe" - $(cat test.sh) 

To może być źle; Nie mogę przetestować tego na tym komputerze. Jeśli zrobisz to bez rury, tak jak próbujesz, grep traktuje ostatni argument jako nazwę pliku, tzn. Szuka pliku o nazwie [contents of test.sh]. Jeśli przekażesz go - (lub nie wstawisz ostatniego argumentu), powiesz mu, aby używał stdin jako pliku.

Można też po prostu przejść grep plik do skanowania przez:

grep "hehe" test.sh 

... ale to wydaje się być pytanie bardziej uogólnionej pytanie bash, naprawdę nie pytanie Wykorzystanie grep, więc to chyba nie zbyt pomocne.

+0

Przyjmuje każde słowo w pliku test.sh i szuka pliku o tej samej nazwie, jak to słowo, i wyświetla te pliki (zwykle z bardzo ograniczonym sukcesem). –

+0

Cofnięcia są podstawiania poleceń tak jak '$()', po prostu nie można zagnieździć i łatwiej zepsuć. Ta ostatnia forma jest prawdopodobnie tym, czego szuka Tim. – Cascabel

+0

Uświadomiłem sobie to; Już edytowałem. : P –

6

Inną formą przekierowania jest podstawienie procesu.

grep "hehe" <(cat test.sh) 

odpowiada:

grep "hehe" test.sh 

oba wyglądają na zawartość samego test.sh.

Chociaż, jak zauważono, to polecenie:

grep "hehe" $(cat test.sh) 

szuka nazw w test.sh i wykorzystuje je jako argumenty dla grep. Więc jeśli test.sh składa się z:

scriptone 
scripttwo 

następnie grep będzie wyglądać na „hehe” w treści każdego z tych plików.

+2

Nie podoba mi się użycie "jest równoważny" na linii 3: "grep" hehe "test.sh" jest, ostatecznie, za pomocą zawartości test.sh jako stdin, podczas gdy 'grep" hehe "<(cat test. sh) 'używa wyjścia polecenia' cat test.sh' jako stdin. Rozważ różnice w wynikach, jeśli uruchomisz komendy w następujący sposób: 'grep -H" hehe "<(cat test.sh)' i 'grep -H" hehe "test.sh' –

1

Co to jest odpowiednik bash pipe za pomocą argumentów wiersza poleceń?

Rury i argumenty linii poleceń są różnymi formami danych wejściowych, które nie są wymienne. Jeśli program pozwala mieć równoważne formy obu, to jest wybór tego samego programu. (W kodzie źródłowym argumenty linii poleceń pojawiają się jako tekst w zmiennej, podczas gdy potoki pojawiają się jako otwarte pliki, w tym stdin i stdout. Składnia przekierowania Bash I/O, jak tutaj użyto później, technicznie robi nie należą do argumentów linii poleceń, choć napisany tuż obok nich w linii poleceń ...)

Ale bądźmy pedantyczny, a także odpowiedzieć na to pytanie:

Co jest odpowiednikiem rury bash bez użycia znaku rury bash?

Odpowiedź: cat test.sh | grep "hehe" odpowiada

grep "hehe" < <(cat test.sh) 

Objaśnienie:

  • Rury przekierowanie stdout jednym poleceniem do standardowego wejścia drugiego. Aby ustawić źródło stdin, możemy użyć przekierowania wejścia (< …) zamiast używać znaku potoku.
  • jednak tylko przy użyciu przekierowanie sygnału (grep "hehe" < test.sh) nie jest to równoznaczne z rur, ponieważ wykorzystuje plik jako źródło dla standardowego wejścia, podczas gdy rury użyć wyjścia polecenia (cat test.sh). W związku z tym dodajemy podstawienie procesu <(…), aby zastąpić dane wejściowe z pliku danymi wejściowymi z polecenia.
  • Oczywiście, przykładem jest mylące, ponieważ oba warianty mają takie same skutki:

    grep "hehe" < test.sh 
    grep "hehe" < <(cat test.sh) 
    

    ale technicznie, wejście z pliku jest jeszcze inny mechanizm niż wejście z wyjściem komendy, która staje się jego wejście z pliku.

Źródło: Advanced Bash Scripting Manual, section on process substitution (rozpocznij czytanie od "Niektóre inne zastosowania").

Powiązane problemy