Come unire e reindirizzare i risultati da due diversi comandi a singolo comando?


35

Voglio unire l'unione (unione) da due diversi comandi e collegarli a un singolo comando.

Un esempio sciocco:

Comandi Voglio unire l'output:

cat wordlist.txt
ls ~/folder/*

in:

wc -l

In questo esempio, se wordlist.txt contiene 5 righe e 3 file, voglio wc -lrestituire 8.

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

Come lo faccio?

Risposte:


56

La tua unione magica è un punto e virgola ... e parentesi graffe:

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

Le parentesi graffe raggruppano solo i comandi insieme, in modo che il segno del tubo |influisca sull'output combinato.

È inoltre possibile utilizzare le parentesi ()attorno a un gruppo di comandi, che eseguirà i comandi in una subshell. Questo ha una sottile serie di differenze con le parentesi graffe, ad esempio provare quanto segue:

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

Vedrai che tutte le variabili di ambiente, inclusa la directory di lavoro corrente, vengono ripristinate dopo essere uscite dal gruppo parentesi, ma non dopo essere uscite dal gruppo parentesi graffa.

Per quanto riguarda il punto e virgola, le alternative includono i segni &&e ||, che eseguiranno in modo condizionale il secondo comando solo se il primo ha esito positivo o, in caso contrario, rispettivamente, ad es.

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

1
Funziona! Aiutami a imparare: cosa fanno esattamente le parentesi graffe qui? Quali altri poteri magici hanno?
David Oneill

@DavidOneill { list; }è un comando composto . Da bash(1): list viene semplicemente eseguito nell'attuale ambiente shell. l'elenco deve essere terminato con una nuova riga o punto e virgola. [..] Lo stato di ritorno è lo stato di uscita dell'elenco.
Lekensteyn,

Ho aggiunto un po 'più di informazioni alla risposta. La guida definitiva allo shell scripting con bash è la manpage bash, digita man bashdalla riga di comando e sfogliala.
pablomme,

dovrebbe il; in quei comandi non essere && se il file wordlist.txt non esiste?
Rinzwind

Se wordlist.txtnon esiste un errore cat, apparirà sull'errore standard, ma non sull'output standard, quindi wc -lnon conterà alcuna riga da esso. Lo stesso vale per ~/foldernon esistente. Si potrebbe aggiungere 2> /dev/nulltra ciascuno di questi comandi e il loro punto e virgola per evitare disturbi in caso di errore standard, ma oltre ad essere brutti, i messaggi di errore sono innocui ai fini del conteggio delle righe.
Pablomme,

8

Poiché wcaccetta un percorso di file come input, è anche possibile utilizzare la sostituzione del processo:

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

Questo equivale all'incirca a:

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

Ricorda che ls ~/folder/*restituisce anche i contenuti delle sottodirectory (se presenti) (a causa dell'espansione globale). Se vuoi solo elencare il contenuto di ~/folder, basta usare ls ~/folder.


L' wc -lera solo un esempio di fatta, io sono in realtà tubazioni in qualcosa di più complicato che non dispone di questa opzione.
David Oneill

2
@DavidOneill Bene, come cataccetta un argomento di file, puoi usare cat <(cat wordlist.txt; ls wordlist.txt) | wc -le anche cat wordlist.txt <(ls wordlist.txt) | wc -l. Questo è ovviamente molto brutto, ma dimostra le infinite possibilità con gli strumenti da riga di comando.
Lekensteyn,

1
@DavidOneill Corretto, l'ho corretto ora, grazie.
Lekensteyn,

1
Volete ls ~/folder/che if ~/foldersia un collegamento simbolico lselenca il contenuto della sua destinazione invece del collegamento stesso. A proposito, tutti i lscomandi dovrebbero essere seguiti in -1modo che venga stampato un singolo file per riga e wc -lsia un modo valido per contare i file.
pablomme,

@pablomme Sei sincero riguardo al collegamento simbolico, ma -1è implicito poiché l'output non è un terminale ma una pipe.
Lekensteyn,

2

Mi ponevo la stessa domanda e ho finito per scrivere una breve sceneggiatura.

magicalUnionThing(Lo chiamo append):

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

Rendi eseguibile quello script

chmod +x ./magicalUnionThing

Ora fallo tu

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

Cosa fa:

  • Invia input standard a output standard
  • Esegui argomento. $*restituisce tutti gli argomenti come una stringa. L'output di quel comando va di default allo script di output standard.

Quindi lo stdout di magicalUnionThing sarà il suo stdin + stdout del comando che viene passato come argomento.

Esistono ovviamente modi più semplici, come per le altre risposte.
Forse questa alternativa può essere utile in alcuni casi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.