Come usare> in un comando xargs?


160

Voglio trovare un comando bash che mi permetta di grep ogni file in una directory e scrivere l'output di quel grep in un file separato. La mia ipotesi sarebbe stata quella di fare qualcosa del genere

ls -1 | xargs -I{} "grep ABC '{}' > '{}'.out"

ma, per quanto ne so, a xargs non piacciono le doppie virgolette. Se rimuovo le virgolette, tuttavia, il comando reindirizza l'output dell'intero comando su un singolo file chiamato '{}'. Out anziché su una serie di singoli file.

Qualcuno sa un modo per farlo usando xargs? Ho appena usato questo scenario grep come esempio per illustrare il mio problema con xargs, quindi tutte le soluzioni che non usano xargs non sono applicabili per me.

Risposte:


201

Non commettere l'errore di fare questo:

sh -c "grep ABC {} > {}.out"

Questo si spezzerà in molte condizioni, inclusi nomi di file funky ed è impossibile citare bene. Devi {}sempre essere un singolo argomento completamente separato al comando per evitare bug di iniezione di codice. Quello che devi fare è questo:

xargs -I{} sh -c 'grep ABC "$1" > "$1.out"' -- {}

Si applica xargsanche a find.

A proposito, non usare mai xargs senza l' -0opzione (a meno che per un uso interattivo una tantum molto controllato e controllato in cui non sei preoccupato di distruggere i tuoi dati).

Inoltre non analizzare ls. Mai. Usa il globbing o findinvece:http://mywiki.wooledge.org/ParsingLs

Utilizzare findper tutto ciò che richiede ricorsione e un semplice ciclo con un glob per tutto il resto:

find /foo -exec sh -c 'grep "$1" > "$1.out"' -- {} \;

o non ricorsivo:

for file in *; do grep "$file" > "$file.out"; done

Si noti l'uso corretto delle virgolette.


Eseguito l'upgrade ma un dubbio regd. non usare xargssenza -0: questo vale solo quando si esegue findl'output di pipe con xargs, giusto? quando faccio xargs -a <input_file>come dovrei usarlo? La maggior parte dei comandi come grepoutput con \ne non \0.L'unico modo in cui mi viene in mente di aggirare questo problema è di trriutilizzarlo per risolvere forse. Ma perché è importante usarlo solo con -0?
legends2k,

3
@ legends2k perché quando non lo usi -0, xargsprenderà i tuoi nomi di file e spezzerà tutti gli spazi, le virgolette e le barre rovesciate. Dovresti semplicemente dimenticartene xargscome uno strumento. Se hai linee, usa un ciclo bash per iterare le linee while read line; do <command> "$REPLY"; done < file-with-linescommand | while ...
:,

1
Wow, non lo sapevo, grazie per il dettaglio! Quindi per la portabilità (poiché non tutti xargssono GNU), xargsdeve essere evitato a meno che non si possa usarlo con -0. Grazie.
legends2k,

1
Anche se apprezzo la spiegazione dettagliata di questo specifico caso d'uso, la domanda riguarda il reindirizzamento dell'output di xargs, che non implica sempre l'analisi lso l'utilizzo sh -c. Questo non risponde minimamente alla domanda, ma è il primo risultato di Google per la domanda, solo aggiungendo alla confusione.
Pandasauce,

1
@Ihunath, ciao, la tua risposta funziona bene per me. Ma potresti dare qualche spiegazione dettagliata o link su xargs -I{} sh -c 'grep ABC "$1" > "$1.out"' -- {}? In particolare, le regole delle virgolette (doppie) incorporate e il simbolo "-" alla fine. Grazie
Scott Yang,

40

Una soluzione senza xargsè la seguente:

find . -mindepth 1 -maxdepth 1 -type f -exec sh -c "grep ABC '{}' > '{}.out'" \;

... e lo stesso si può fare con xargs , si scopre:

ls -1 | xargs -I {} sh -c "grep ABC '{}' > '{}.out'"

Modifica : virgolette singole aggiunte dopo l'osservazione di lhunath .


Ha detto che vuole usare xargs. Ho pubblicato anche una soluzione senza di essa, ma una volta eliminato ho visto che aveva bisogno di xargs.
Zifre,

Hai ragione. Il motivo per cui ho pubblicato la mia risposta è che è meglio avere una soluzione alternativa per svolgere il lavoro piuttosto che nessuna. Si scopre che mi ha messo sulla strada giusta per trovare la risposta desiderata (cioè il trucco sh -c).
Stephan202,

14

Suppongo che il tuo esempio sia solo un esempio e che potresti aver bisogno di> per altre cose. GNU Parallel http://www.gnu.org/software/parallel/ potrebbe essere il tuo salvataggio. Non è necessario un preventivo aggiuntivo purché i nomi dei file non contengano \ n:

ls | parallel "grep ABC {} > {}.out"

Se hai nomi di file con \ n al suo interno:

find . -print0 | parallel -0 "grep ABC {} > {}.out"

Come bonus aggiuntivo ottieni i lavori eseguiti in parallelo.

Guarda i video introduttivi per saperne di più: http://pi.dk/1

L'installazione in 10 secondi proverà a eseguire un'installazione completa; se fallisce, un'installazione personale; se fallisce, un'installazione minima:

$ (wget -O - pi.dk/3 || lynx -source pi.dk/3 || curl pi.dk/3/ || \
   fetch -o - http://pi.dk/3 ) > install.sh
$ sha1sum install.sh | grep 3374ec53bacb199b245af2dda86df6c9
12345678 3374ec53 bacb199b 245af2dd a86df6c9
$ md5sum install.sh | grep 029a9ac06e8b5bc6052eac57b2c3c9ca
029a9ac0 6e8b5bc6 052eac57 b2c3c9ca
$ sha512sum install.sh | grep f517006d9897747bed8a4694b1acba1b
40f53af6 9e20dae5 713ba06c f517006d 9897747b ed8a4694 b1acba1b 1464beb4
60055629 3f2356f3 3e9c4e3c 76e3f3af a9db4b32 bd33322b 975696fc e6b23cfb
$ bash install.sh

Se è necessario spostarlo su un server su cui non è installato GNU Parallel, provare parallel --embed.

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.