Ausführen eines Befehls für viele Dateien


19

Ich habe einen Ordner mit vielen Dateien (xyz1, xyz2, bis zu xyz5025) und muss auf jedem ein Skript ausführen, um xyz1.faa, xyz2.faa usw. als Ausgabe zu erhalten.

Der Befehl für eine einzelne Datei lautet:

./transeq xyz1 xyz1.faa -table 11

Gibt es eine Möglichkeit, das automatisch zu tun? Vielleicht eine For-Do-Combo?

Antworten:


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

Dies ist eine einfache forSchleife, die jede Datei durchläuft, die xyzim aktuellen Verzeichnis beginnt, und das ./transeqProgramm mit dem Dateinamen als erstem Argument aufruft, gefolgt von ".faa" als zweitem Argument, gefolgt von "-table 11". .


4
Oder als Einzeiler: for file in xyz*; do ./transeq "$file" "${file}.faa" -table 11; done. Ich schreibe die ganze Zeit so etwas. Und wenn Sie überprüfen möchten, ob die Dateinamen usw. wie gewünscht erweitert werden, setzen Sie echonach dodem ersten Mal ein Rechtszeichen und gehen Sie dann zurück in Ihren Shell-Verlauf und löschen Sie ihn beim zweiten Mal.
Dave Tweed

"$file".faaist als Teil eines interaktiven Einzeilers etwas einfacher einzugeben und sicher, da .faaes keine Shell-Metazeichen enthält, die in Anführungszeichen gesetzt werden müssen.
Peter Cordes

2
Wenn Sie am Ende einen xyz*Teillauf durchführen und die Schleife neu starten möchten, nimmt der Glob auch .faa-Dateien auf. Führen Sie für bash shopt -s extglob( reference ) aus und for file in xyz!(*.faa) ...schließen Sie dann die .faa-Dateien vom Senden durch die Schleife aus.
Jeff Schaller

24

Wenn Sie GNU Parallel installieren , können Sie dies wie folgt parallel tun:

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

Wenn Ihr Programm CPU-intensiv ist, sollte es ziemlich schnell laufen.


6

Sie können so etwas in einer bashBefehlszeile ausführen:

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

Wir generieren die Ganzzahlen von 1 bis 5025, one / line, {}und geben sie dann einzeln an xargs weiter, wobei die Ganzzahl in ./transeq eingekapselt und dann in geeigneter Weise in die Befehlszeile transplantiert wird.

Wenn Sie nicht über die Möglichkeit zur Klammererweiterung verfügen, können {n..m}Sie das seqDienstprogramm aufrufen , um diese Zahlen zu generieren.

Oder Sie können die numerische Generierung immer emulieren über:

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

1
Das ist viel zu kompliziert. for i in {1..5025}; do ./transeq "xyz$i" "xyz$i".faa -table 11; doneist viel einfacher zu denken und zu tippen. Wenn Sie möchten, dass Befehle vor dem Ausführen gedruckt werden, verwenden Sie set -x.
Peter Cordes

Ja, das stimmt, aber die Art und Weise, wie das OP die Frage formulierte, schien mir nur die Dateien mit den Namen xyz1 .. xyz5025 von Interesse zu sein. Also dachte ich, wenn wir es mit xyz * machen, brauchen wir eine Möglichkeit, die nicht konformen Dateien abzulehnen. Idealerweise, wenn das OP alle Dateien in einem Verzeichnis verarbeiten möchte, warum dann die 1 bis 5025-Sache aufrufen? Sagen Sie einfach, dass ich möchte, dass alle Dateien auf vorgeschriebene Weise verarbeitet werden, das wäre ausreichend gewesen.

1
Schau dir die Schleife an, die ich geschrieben habe. Damit for i in {1..5025}erzielen Sie genau das gleiche Ergebnis wie bei Ihnen. Sie könnten auch for ((i=1 ; i<=5025 ; i++)); do ./transeq "xyz$i" "xyz$i".faa -table 11; donein Bash schreiben , aber ich verwende normalerweise die {a..b}Range-Syntax, weil es schneller zu tippen ist.
Peter Cordes

4

Die Verwendung von find ist nützlich, wenn sich Ihre Dateien in Verzeichnissen befinden

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

4

Angenommen, Sie haben mehr als einen Kern und jeder Aufruf kann unabhängig von den anderen ausgeführt werden, werden Sie mit parallelen Läufen eine ziemliche Beschleunigung erzielen.

Ein relativ einfacher Weg, dies zu tun, ist über den -PParameter von xargs- zum Beispiel, wenn Sie 4 Kerne haben:

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

Das -n 1befiehlt xargs, für jeden Aufruf nur ein Argument aus der Liste auszuwählen (standardmäßig würde es viel passieren) , und das -P 4befiehlt, 4 Prozesse gleichzeitig zu erzeugen - wenn einer stirbt, wird ein neuer erzeugt.

IMHO, Sie müssen GNU für diesen einfachen Fall nicht parallel installieren - xargsreicht aus.


0

Sie können verwenden xarg

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

-L 1 Bewirkt, dass jeweils 1 Element übergeben wird

-d '\n'make output of lswird basierend auf der neuen Zeile aufgeteilt.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.