Jak scalić i potokować wyniki z dwóch różnych poleceń do pojedynczego polecenia?


35

Chcę scalić dane wyjściowe z dwóch różnych poleceń i połączyć je w jedno polecenie.

Głupi przykład:

Polecenia, które chcę scalić dane wyjściowe:

cat wordlist.txt
ls ~/folder/*

w:

wc -l

W tym przykładzie, jeśli wordlist.txt zawiera 5 linii i 3 pliki, chcę wc -lzwrócić 8.

$cat wordlist.txt *[magical union thing]* ls ~/folder/* | wc -l
8

W jaki sposób mogę to zrobić?

Odpowiedzi:


56

Twoje magiczne połączenie to średnik ... i nawiasy klamrowe:

    { cat wordlist.txt ; ls ~/folder/* ; } | wc -l

Nawiasy klamrowe grupują tylko polecenia, dzięki czemu znak potoku |wpływa na łączny wynik.

Możesz także użyć nawiasów ()wokół grupy poleceń, które wykonałyby polecenia w podpowłoce. Jest to subtelny zestaw różnic z nawiasami klamrowymi, np. Wypróbuj następujące czynności:

    cd $HOME/Desktop ; (cd $HOME ; pwd) ; pwd
    cd $HOME/Desktop ; { cd $HOME ; pwd ; } ; pwd

Zobaczysz, że wszystkie zmienne środowiskowe, w tym bieżący katalog roboczy, są resetowane po wyjściu z grupy nawiasów, ale nie po wyjściu z grupy nawiasów klamrowych.

Jeśli chodzi o średnik, alternatywami są znaki &&i ||, które warunkowo wykonają drugie polecenie tylko wtedy, gdy pierwsze zakończy się powodzeniem lub jeśli nie, np.

    cd $HOME/project && make
    ls $HOME/project || echo "Directory not found."

1
To działa! Pomóż mi się nauczyć - co dokładnie robią tutaj nawiasy klamrowe? Jakie inne magiczne moce mają?
David Oneill,

@DavidOneill { list; }to polecenie złożone . Od bash(1): lista jest po prostu wykonywana w bieżącym środowisku powłoki. lista musi być zakończona znakiem nowej linii lub średnikiem. [..] Status powrotu to status wyjścia z listy.
Lekensteyn,

Dodałem nieco więcej informacji do odpowiedzi. Ostatecznym przewodnikiem po skryptach powłoki za pomocą bash jest strona podręcznika bash, wpisz man bashz linii poleceń i przejrzyj ją.
pablomme

powinien; w tych poleceniach nie jest && w przypadku, gdy plik wordlist.txt nie istnieje?
Rinzwind

Jeśli wordlist.txtnie istnieje, błąd catpojawi się na standardowym błędzie, ale nie na standardowym wyjściu, więc wc -lnie będzie zliczał żadnych wierszy z niego. To samo dotyczy ~/foldernieistnienia. Można dodać 2> /dev/nullmiędzy każdą z tych komend a ich średnikiem, aby zapobiec zakłóceniom przy standardowym błędzie, ale poza brzydkimi komunikatami o błędach są nieszkodliwe dla zliczania linii.
pablomme

8

Ponieważ wcakceptuje ścieżkę pliku jako dane wejściowe, możesz również użyć podstawienia procesu:

wc -l <(cat wordlist.txt; ls ~/folder/*)

Odpowiada to mniej więcej:

echo wordlist.txt > temp
ls ~/folder/* >> temp
wc -l temp

Pamiętaj, że ls ~/folder/*zwraca również zawartość podkatalogów, jeśli takie istnieją (z powodu globalnej ekspansji). Jeśli chcesz tylko wyświetlić zawartość ~/folder, po prostu użyj ls ~/folder.


To wc -lbył tylko wymyślony przykład, w rzeczywistości instaluję go w coś bardziej skomplikowanego, który nie ma tej opcji.
David Oneill,

2
@DavidOneill Cóż, ponieważ catakceptuje argument pliku, możesz użyć, cat <(cat wordlist.txt; ls wordlist.txt) | wc -la nawet cat wordlist.txt <(ls wordlist.txt) | wc -l. Jest to oczywiście bardzo brzydkie, ale pokazuje nieskończone możliwości dzięki narzędziom wiersza poleceń.
Lekensteyn,

1
@DavidOneill Prawidłowo, poprawiłem to teraz, dzięki.
Lekensteyn,

1
Chcesz ls ~/folder/, aby if ~/folderbył dowiązaniem symbolicznym lswyświetla zawartość jego celu zamiast samego łącza. Nawiasem mówiąc, po wszystkich lspoleceniach powinno następować -1tak, aby drukowany był jeden plik na linię i wc -lbył to prawidłowy sposób zliczania plików.
pablomme

@pablomme Masz rację co do dowiązania symbolicznego, ale -1sugeruje się, że wyjście nie jest terminalem, ale potokiem.
Lekensteyn,

2

Zadawałem sobie to samo pytanie i ostatecznie napisałem krótki scenariusz.

magicalUnionThing(Nazywam to append):

#!/bin/sh
cat /dev/stdin
$*

Spraw, aby ten skrypt był wykonywalny

chmod +x ./magicalUnionThing

Teraz ty

cat wordlist.txt |./magicalUnionThing ls ~/folder/* | wc -l

Co to robi:

  • Wyślij standardowe wejście na standardowe wyjście
  • Wykonaj argument. $*zwraca wszystkie argumenty jako ciąg. Wyjście tej komendy domyślnie przechodzi na standardowe wyjście skryptu.

Stdout magicalUnionThing będzie więc stdin + stdout polecenia przekazanego jako argument.

Istnieją oczywiście prostsze sposoby, jak w przypadku innych odpowiedzi.
Być może ta alternatywa może być przydatna w niektórych przypadkach.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.