Jak potokować wyjście polecenia do innych poleceń?

83

Przykład:

ls | echonie drukuje nic (właściwie pusta linia). Spodziewałbym się, że wydrukuje listę plików.

ls | grep 'foo'z drugiej strony działa zgodnie z oczekiwaniami (drukuje pliki z imieniem „foo”).

To, co robię w takich sytuacjach, jest takie: ls | while read OUT; do echo $OUT; doneale jest to raczej kłopotliwe.

Dlaczego przesyłanie potokowe działa z niektórymi poleceniami, a nie z innymi? Jak mogę obejść ten problem?

Mihai Rotaru
źródło
2
Czego oczekujesz ls | echozrobić? dlaczego po prostu nie uruchomić ls?
theomega
12
Użyłem najprostszego przykładu, który ilustruje mój punkt widzenia. Naprawdę napotkałem ten problem, gdy próbowałem stworzyć jednowierszową, która pokazywałaby obiekty git w magazynie obiektów i ich typ. Więc przesłałem ID obiektu git cat-file, ale to po prostu nie działało. Najwyraźniej echo ma takie samo zachowanie, więc użyłem go jako przykładu.
Mihai Rotaru,
spójrz także na komendę -n dla xargs, mówi ile argumentów umieścić w podkomendie. „... | xargs -n1 git cat-file`
Rich Homolka

Odpowiedzi:

118

Istnieje różnica między argumentami wiersza poleceń a standardowymi danymi wejściowymi. Rura połączy standardowe wyjście jednego procesu ze standardowym wejściem innego. Więc

ls | echo

Łączy standardowe wyjście ls ze standardowym wejściem echa. Dobrze, prawda? Cóż, echo ignoruje standardowe wejście i zrzuci argumenty wiersza poleceń - których w tym przypadku nie ma - na swoje standardowe wyjście. Wynik: w ogóle nic.

W tym przypadku istnieje kilka rozwiązań. Jednym z nich jest użycie polecenia, które odczytuje stdin i zrzuca na standardowe wyjście, takie jak cat.

ls | cat

Będzie „działać”, w zależności od twojej definicji pracy.

Ale co z ogólnym przypadkiem. Naprawdę chcesz przekonwertować standardowe wyjście jednego polecenia na argumenty wiersza poleceń innego. Jak powiedzieli inni, xargsjest kanonicznym narzędziem pomocniczym w tym przypadku, czytając jego linię poleceń argumentów dla polecenia ze standardowego wejścia i konstruując polecenia do uruchomienia.

ls | xargs echo

Można to również przekonwertować za pomocą polecenia podstawienia $()

echo $(ls)

Zrobiłbym również, co chcesz.

Oba te narzędzia są bardzo ważne dla skryptów powłoki, powinieneś nauczyć się obu.

Dla kompletności, jak wskazano w pytaniu, innym podstawowym sposobem konwersji stdin na argumenty linii poleceń jest wbudowane readpolecenie powłoki . Konwertuje „słowa” (słowa zdefiniowane przez IFSzmienną) na zmienną tymczasową, której można używać w dowolnych uruchomieniach poleceń.

Rich Homolka
źródło
1
Bardzo pomocna odpowiedź informacyjna, dziękuję! Obecnie uczę się bash i widziałem wcześniej zarówno xargs, jak i notację $ (*), ale nie zwracałem na nie dużej uwagi. Teraz wiem, jak ważne są i na pewno się nimi zajmę.
Mihai Rotaru,
1
xargs mógł być tym, czego szukał OP.
Iktys
19

ls | echowypisuje tylko pustą linię, ponieważ echonie czyta żadnych danych wejściowych; ostatnią komendą potoku jest to, echoże drukuje tylko pustą linię.

Ogólnie:

a | b

upewnia się, że dane wyjściowe astają się danymi wejściowymi b. Proponuję przeczytać Pipelinessekcję man bash.


Jeśli naprawdę chcesz używać lsi echorazem oto kilka (całkiem bezużytecznych) przykładów:

ls | xargs -L 1 echo
echo `ls`
for i in `ls` ; do echo $i ; done
Cyrus
źródło
11

Jeśli chcesz, aby echow lspróbie polecenia:

ls | xargs echo

To wywoła echoz wyjściem ls.

Nathan Fellman
źródło
3
Lub ls | xargs -I {} echo {}jeśli chcesz, aby był wywoływany dla każdej linii osobno
Alex Abdugafarov
3

Dlaczego nie po prostu użyć:

echo `ls`

Lub o wiele bezpieczniej:

echo "`ls -lrt`"
Urbwzrd
źródło
4
A nawet po prostu echo *.
Kazark