Combina più comandi unix in un unico output


9

Devo cercare nei registri della posta un indirizzo e-mail specifico. Conserviamo un file corrente chiamato maillog e una settimana di file .bz2 nella stessa cartella. Attualmente sto eseguendo i seguenti comandi per cercare il file:

grep person@domain.com maillog
bzgrep person@domain.com *.bz2

C'è un modo per combinare i comandi grepe bzgrepin un singolo output? In questo modo, potrei reindirizzare i risultati combinati a una singola e-mail o un singolo file.

Risposte:


24

Un altro modo è

{ grep ...; bzgrep ...;} >file

&&ha la difficoltà che il bzgrepnon verrebbe eseguito se il grepfallito.

Nota lo spazio obbligatorio dopo l'apertura parentesi graffa e punto e virgola dopo l'ultimo comando. In alternativa, è possibile utilizzare la sintassi subshell (parentesi anziché parentesi graffe), che non è così esigente:

(grep ...; bzgrep ...) >file

+1 per il miglior approccio generale della shell a questo problema. Il raggruppamento delle shell è una funzionalità generalmente sottoutilizzata.
Phil Hollenback,

2
Non intendi ()invece {}?
Ehtesh Choudhury,

Su Arch Linux questo ha funzionato, ()ma non in {}entrambi i casi, poiché questo è ciò di cui avevo bisogno!
Chris Magnuson,

11

bzgrep si imposta automaticamente su grep normale se un file non è compresso con bzip. Pertanto, dovrebbe essere sufficiente:

bzgrep person@domain.com maillog *bz2 | mail -s "logs yay" someuser@blah

oh, ovviamente, ecco anche la mia soluzione parallela GNU obbligatoria :

parallel -m bzgrep person@domain.com ::: maillog* *bz2 | mail -s "logs yay" someuser@blah

che potrebbe essere molto più veloce se stai controllando molti file.


2

Ecco un altro modo per farlo (supponendo che tu stia eseguendo bash, cosa che probabilmente sei):

cat <(bzgrep ...) <(grep ...)

Qui bash sta alimentando in modo trasparente l'output dei comandi bzgrep e grep in cat come se fossero file (e in qualche modo sono sotto il cofano, i dettagli nell'URL in basso).

Nel tuo caso particolare consiglierei la soluzione di Phil, ma quanto sopra è un buon trucco da tenere nella borsa.

Se sei interessato, puoi leggere di più qui: http://www.tldp.org/LDP/abs/html/process-sub.html


Ah sì, la risposta canonica per "come si differenzia l'output di due processi". Un buon trucco da sapere.
Phil Hollenback,

1

Al momento della mia stesura di questo, la sintassi della risposta accettata era errata per la maggior parte, se non per tutte, le shell derivate da Bourne, incluso bash. Ho suggerito una modifica all'inizio e ho accettato la risposta per risolverlo, ma ero anche incline ad aggiungere tutte queste altre informazioni, e questo sarebbe stato più una riscrittura che una modifica.

Puoi usare i comandi composti:

{ grep ...; bzgrep ...; } >file

..o subshells (notare le parentesi anziché le parentesi graffe):

(grep ...; bzgrep ...) >file

..per raggruppare i comandi. Il modo subshell ha una sintassi migliore (più tollerante della mancanza di spazi bianchi e consente di omettere l'ultimo punto e virgola), ma o forgia un nuovo processo, o "finge" di farlo eseguire i comandi in un ambiente pulito. Entrambi hanno vantaggi a seconda di ciò che si desidera fare, che non importa qui, ma vale la pena cercare se si desidera una maggiore competenza con la shell.

Nota: puoi usare il pipelining anche con questi trucchi, quindi potresti fare qualcosa del genere:

{ grep ...; bzgrep ...; } | less

PS se non si preoccupano l'ordinamento delle partite in vostro output combinato, è possibile utilizzare un unico &tra i due comandi, in questo modo: { grep ... & bzgrep ...; }. Quindi i due comandi vengono eseguiti contemporaneamente: grepviene avviato e la shell lo mette in background, quindi la shell eseguirà il bzgrep. (Ma c'è un piccolo avvertimento a riguardo, con la spiegazione che riguarda il reindirizzamento dei file e il buffering del flusso di file potenzialmente causando una porzione molto piccola delle righe nel file di output da dividere / alterare: se vedresti che ciò dipenderà da come grep, bzgrepe le libc stdio.hfunzioni sono implementate. Nella maggior parte delle implementazioni, credo che reindirizzare il comando prima di reindirizzare a un file eviterà il problema, quindi potresti fare { foo & bar; } | cat - >fileuna soluzione alternativa.)


0

È possibile associare i comandi a && che consentiranno di eseguire ciascun comando.

potresti anche aggiungere >> textfile.txt alla fine di ogni comando e fare in modo che l'output colpisca un file e poi lo spedisca.


2
Come menzionato da geekosaur, && non dovrebbe essere usato qui perché il valore di ritorno di grep dipende dal fatto che abbia trovato qualcosa o meno. Se lo facessi grep ... && bzgrep ..., se grep non avesse riscontri, restituirebbe un errore e il comando si fermerebbe. >>è una buona idea, tuttavia, a differenza >, aggiungerà l'output alla fine di un file esistente.
DerfK

giusto mi ero dimenticato della condizione di uscita che impediva il secondo comando.
Mike
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.