Esecuzione di un comando su molti file


19

Ho una cartella con molti file (xyz1, xyz2, fino a xyz5025) e ho bisogno di eseguire uno script su ognuno di essi, ottenendo xyz1.faa, xyz2.faa e così via come output.

Il comando per un singolo file è:

./transeq xyz1 xyz1.faa -table 11

C'è un modo per farlo automaticamente? Forse una combinazione for-do?

Risposte:


32
for file in xyz*
do
  ./transeq "$file" "${file}.faa" -table 11
done

Questo è un semplice forciclo che ripeterà ogni file che inizia xyznella directory corrente e chiamerà il ./transeqprogramma con il nome file come primo argomento, il nome file seguito da ".faa" come secondo argomento, seguito da "-table 11" .


4
Oppure, come un one-liner: for file in xyz*; do ./transeq "$file" "${file}.faa" -table 11; done. Scrivo questo genere di cose tutto il tempo. E se vuoi verificare che i nomi dei file, ecc. Si stiano espandendo nel modo desiderato, inseriscili echosubito dopo dola prima volta, quindi torna indietro nella cronologia della shell ed eliminali la seconda volta.
Dave Tweed,

"$file".faaè leggermente più facile da digitare come parte di un one-liner interattivo e sicuro perché .faanon contiene metacaratteri di shell che devono essere citati.
Peter Cordes,

2
Come nota, se si finisce con una corsa parziale e si desidera riavviare il ciclo, il xyz*glob raccoglierà anche i file .faa. Per bash, esegui shopt -s extglob( riferimento ), quindi usa for file in xyz!(*.faa) ...per escludere i file .faa dall'invio attraverso il ciclo.
Jeff Schaller

24

Se installi GNU Parallel puoi farlo in parallelo in questo modo:

parallel ./transeq {} {}.faa -table 11 ::: xyz*

Se si programma ad alta intensità di CPU, dovrebbe accelerare un po '.


6

Puoi fare qualcosa del genere su una bashriga di comando:

printf '%s\n' {1..5025} | xargs -l -I {} -t ./transeq xyz{} xyz{}.faa -table 11

Stiamo generando gli interi da 1 a 5025, uno / riga, quindi alimentandoli uno a uno a xargs, che incapsula l'intero in {}e quindi lo trapianta nella riga di comando ./transeq in modo appropriato.

Se non si dispone della funzione di espansione della parentesi graffa, {n..m}è possibile richiamare l' sequtilità per generare tali cifre.

Oppure puoi sempre emulare la generazione numerica tramite:

yes | sed -n =\;5025q | xargs ...

1
È troppo complicato. for i in {1..5025}; do ./transeq "xyz$i" "xyz$i".faa -table 11; doneè molto più facile da pensare e digitare. Se si desidera stampare i comandi prima di eseguirli, utilizzare set -x.
Peter Cordes,

Sì, è corretto, ma il modo in cui l'OP ha formulato la domanda mi è sembrato interessante solo i file con i nomi xyz1 .. xyz5025. Quindi ho pensato che se lo facciamo usando xyz * allora avremmo bisogno di un modo per rifiutare i file non conformi ... da qui. Idealmente se l'OP vuole che tutti i file in una directory vengano elaborati, allora perché visualizzare la cosa da 1 a 5025? Basta dire che voglio che tutti i file elaborati in modo prescritto siano stati sufficienti.

1
Guarda il ciclo che ho scritto. Usa for i in {1..5025}per ottenere esattamente lo stesso risultato del tuo. Puoi anche scrivere for ((i=1 ; i<=5025 ; i++)); do ./transeq "xyz$i" "xyz$i".faa -table 11; donein bash, ma di solito uso la {a..b}sintassi dell'intervallo perché è più veloce da scrivere.
Peter Cordes,

4

Utilizzando find, utile quando i file sono sparsi all'interno delle directory

find -name "xyz*" -exec ./transeq {} {}.faa -table 11 \;

4

Supponendo di avere più di un core e che ogni invocazione possa essere eseguita indipendentemente dalle altre, si otterrà una maggiore velocità con corse parallele.

Un modo relativamente semplice per farlo è tramite il -Pparametro di xargs- ad esempio, se hai 4 core:

echo xyz{1..5025} | \
    xargs -n 1 -P 4 -I{} /path/to/transeq xyz{} xyz{}.faa -table 11

La -n 1dice xargsdi scegliere un solo argomento fuori dalla lista per ogni invocazione (di default sarebbe passato un sacco) , e la -P 4dice di deporre le uova 4 processi allo stesso tempo - quando uno muore, uno nuovo viene generato.

IMHO, non è necessario installare GNU parallelo per questo semplice caso - è xargssufficiente.


0

Puoi usare xarg

ls | xargs -L 1 -d '\n' your-desired-command

-L 1 fa passare 1 oggetto alla volta

-d '\n'rendere l'output di lsè diviso in base alla nuova riga.

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.