web-dev-qa-db-fra.com

BASH: comment boucler tous les fichiers en ordre de tri

Je boucle tous les fichiers du répertoire avec la commande suivante:

for i in *.fas; do some_code; done;

Cependant, je reçois ordre comme ceci:

vvchr1.fas
vvchr10.fas
vvchr11.fas

au lieu de vvchr1.fas, vvchr2.fas, vvchr3.fas, quel est l'ordre numérique.

J'ai essayé de trier la commande, mais sans succès.

41
Perlnika
for i in `ls *.fas | sort -V`; do some_code; done;

sort -V fait selon man sort une sorte de version - une sorte naturelle de nombres (version) dans le texte

Le même en utilisant seulement ls:

for i in `ls -v *.fas`; do echo $i; done;
75
catalin.costache

Vous obtiendrez les fichiers dans l'ordre ASCII. Cela signifie que vvchr10* vient avant vvchr2*. Je me rends compte que vous ne pouvez pas renommer vos fichiers (mon cerveau bioinformaticien me dit qu’ils contiennent des données chromosomiques, et nous n’appelons tout simplement pas le chromosome 1 "chr01"). Voici donc une autre solution (ne pas utiliser sort -V que je ne trouve sur aucun système d'exploitation que j'utilise):

ls *.fas | sed 's/^\([^0-9]*\)\([0-9]*\)/\1 \2/' | sort -k2,2n | tr -d ' ' |
while read filename; do
  # do work with $filename
done

Ceci est un peu compliqué et ne fonctionnera pas avec les noms de fichiers contenant des espaces.

Une autre solution: supposons que nous voulions parcourir les fichiers par ordre de taille, ce qui serait peut-être plus approprié pour certaines tâches de bioinformatique:

du *.fas | sort -k2,2n |
while read filesize filename; do
  # do work with $filename
done

Pour inverser le tri, ajoutez simplement r après -k2,2n (pour obtenir -k2,2nr).

4
Kusalananda

Avec l'option sort -g il compare en fonction de la valeur numérique générale

 for FILE in `ls ./raw/ | sort -g`; do echo "$FILE"; done

0.log 1.log 2.log ... 10.log 11.log

Cela ne fonctionnera que si le nom des fichiers est numérique. S'ils sont ficelés, vous les obtiendrez dans l'ordre alphabétique. Par exemple.:

 for FILE in `ls ./raw/* | sort -g`; do echo "$FILE"; done

raw/0.log raw/10.log raw/11.log ... raw/2.log

3
gtangil
while IFS= read -r  file ; do
    ls -l "$file" # or whatever
done < <(find . -name '*.fas' 2>/dev/null | sed -r -e 's/([0-9]+)/ \1/' | sort -k 2 -n | sed -e 's/ //;'

Résout le problème, en supposant que la dénomination des fichiers reste cohérente, ne repose pas sur des versions très récentes de GNU sort, ne repose pas sur la lecture du résultat de ls et ne soit pas victime de la filiation problèmes.

1
Sorpigal

Vous voulez dire que les fichiers avec le numéro 10 viennent avant les fichiers avec le numéro 3 dans votre liste? C’est parce que ls trie très simplement le résultat, donc something-10.whatever est plus petit que something-3.whatever.

Une solution consiste à renommer tous les fichiers pour qu'ils aient le même nombre de chiffres (les fichiers contenant un seul chiffre commencent par 0 dans le numéro).

1

Comme la solution de @ Kusalananda (peut-être plus facile à retenir?) Mais pour tous les fichiers (?):

array=("$(ls |sed 's/[^0-9]*\([0-9]*\)\..*/\1 &/'| sort -n | sed 's/^[^ ]* //')")
for x in "${array[@]}";do echo "$x";done

Essentiellement, ajoutez une clé de tri, triez, supprimez la clé de tri.

EDIT: commentaire déplacé vers la solution appropriée

0
potong

utiliser sort -rh et la boucle while

du -sh * | sort -rh | grep -P "avi$" |awk '{print $2}' | while read f; do fp=`pwd`/$f; echo $fp; done;
0
David Okwii