Exécution d'une commande sur de nombreux fichiers


19

J'ai un dossier avec de nombreux fichiers (xyz1, xyz2, jusqu'à xyz5025) et j'ai besoin d'exécuter un script sur chacun d'eux, obtenant xyz1.faa, xyz2.faa, etc. en tant que sorties.

La commande pour un seul fichier est:

./transeq xyz1 xyz1.faa -table 11

Existe-t-il un moyen de le faire automatiquement? Peut-être un combo à faire?

Réponses:


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

Il s'agit d'une simple forboucle qui itérera sur chaque fichier commençant par xyzdans le répertoire en cours et appellera le ./transeqprogramme avec le nom de fichier comme premier argument, le nom de fichier suivi de ".faa" comme deuxième argument, suivi de "-table 11" .


4
Ou, comme un paquebot: for file in xyz*; do ./transeq "$file" "${file}.faa" -table 11; done. Je tape ce genre de chose tout le temps. Et si vous voulez vérifier que les noms de fichiers, etc. sont étendus comme vous le souhaitez, mettez simplement un echodroit après dola première fois, puis revenez dans votre historique de shell et supprimez-le une deuxième fois.
Dave Tweed

"$file".faaest légèrement plus facile à taper dans le cadre d'un one-liner interactif et sûr car .faail ne contient aucun métacaractère shell à citer.
Peter Cordes du

2
Remarque: si vous vous retrouvez avec une exécution partielle et que vous souhaitez redémarrer la boucle, le xyz*glob récupère également les fichiers .faa. Pour bash, exécutez shopt -s extglob( référence ), puis utilisez for file in xyz!(*.faa) ...pour exclure les fichiers .faa d'être envoyés via la boucle.
Jeff Schaller

24

Si vous installez GNU Parallel, vous pouvez le faire en parallèle comme ceci:

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

Si votre programme est gourmand en CPU, il devrait accélérer un peu.


6

Vous pouvez faire quelque chose comme ça sur une bashligne de commande:

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

Nous générons les entiers de 1 à 5025, un / ligne, puis {}les alimentons un par un aux xargs, qui encapsule l'entier dans puis le transplante dans la ligne de commande ./transeq de manière appropriée.

Si vous ne disposez pas de la fonction d'expansion d'accolade, {n..m}vous pouvez invoquer l' sequtilitaire pour générer ces chiffres.

Ou, vous pouvez toujours émuler la génération numérique via:

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

1
C'est beaucoup trop compliqué. for i in {1..5025}; do ./transeq "xyz$i" "xyz$i".faa -table 11; doneest beaucoup plus facile à penser et à taper. Si vous souhaitez qu'il imprime des commandes avant de les exécuter, utilisez set -x.
Peter Cordes

Oui, c'est exact, mais la façon dont l'OP a formulé la question m'a semblé que seuls les fichiers avec les noms xyz1 .. xyz5025 étaient intéressants. J'ai donc pensé que si nous le faisons en utilisant pour xyz *, nous avons besoin d'un moyen de rejeter les fichiers non conformes ... d'où cela. Idéalement, si l'OP souhaite que tous les fichiers d'un répertoire soient traités, pourquoi faire apparaître la chose 1 à 5025? Dites simplement que je veux que tous les fichiers traités de la manière prescrite aient été suffisants.

1
Regardez la boucle que j'ai écrite. Il utilise for i in {1..5025}pour obtenir exactement le même résultat que le vôtre. Vous pouvez également écrire for ((i=1 ; i<=5025 ; i++)); do ./transeq "xyz$i" "xyz$i".faa -table 11; doneen bash, mais j'utilise généralement la {a..b}syntaxe de la plage car elle est plus rapide à taper.
Peter Cordes du

4

Utilisation de find, utile lorsque vos fichiers sont dispersés dans des répertoires

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

4

En supposant que vous avez plus d'un cœur et que chaque invocation puisse s'exécuter indépendamment des autres, vous obtiendrez une accélération considérable avec des exécutions parallèles.

Un moyen relativement simple de le faire est via le -Pparamètre de xargs- par exemple, si vous avez 4 cœurs:

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

Le -n 1dit xargsde ne choisir qu'un seul argument de la liste pour chaque invocation (par défaut, il passerait beaucoup) , et le -P 4dit de générer 4 processus en même temps - quand on meurt, un nouveau est généré.

À mon humble avis, vous n'avez pas besoin d'installer parallèle GNU pour ce cas simple - xargssuffit.


0

Vous pouvez utiliser xarg

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

-L 1 fait passer 1 élément à la fois

-d '\n'make output of lsest divisé en fonction de la nouvelle ligne.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.