Forum Programmation.shell Trier une liste sur une partie du nom

Posté par .
Tags :
1
4
oct.
2012

Bonjour,

Je recherche une méthode en SHELL permettant de trier une liste de noms de fichiers. Toutes les commandes de base sont permises (ls, grep, sort, sed, awk, …)

Liste à trier contenu dans le fichier FOO.TXT :

01_ceci_est_le_nom_d_un_fichier_20121004_100000.txt
02_cela_est_un_autre_fichier_20111003_110000.csv
03_encore_un_autre_fichier_20121002_090000.tar
04_et_un_petit_dernier_pour_la_route_20121212_121212.tgz

Il faut que la commande magique puisse trier uniquement sur la partie 'YYYYMMJJ' pour donner :

02_cela_est_un_autre_fichier_20111003_110000.csv
03_et_encore_un_autre_fichier_20121002_090000.tar
01_ceci_est_le_nom_d_un_fichier_20121004_100000.txt
04_et_un_petit_dernier_pour_la_route_20121212_121212.tgz

La seul règle commune aux 4 noms de fichier de la liste est que les noms se terminent tous de la même façon '_YYYYMMJJ_HHMMSS.ext' (avec 20 caractères en partant de la fin)

Merci d'avance à ceux qui pourront me venir en aide car je sèche grave !

  • # Par exemple

    Posté par . Évalué à 10. Dernière modification le 04/10/12 à 17:14.

    ls -1 | awk -F_ '{print $(NF-1) " " $0}' | sort | cut -d' ' -f2-
    
    

    Edit: explication

    • ls -1 : un fichier par ligne
    • awk :
      ** Découpage :
      *** -F_ : le séparateur de champs est _
      *** NF-1 : numéro de l'avant-dernier champ
      *** $(NF-1) : contenu de l'avant-dernier champ
      *** $0 : contenu complet de l'enregistrement (ligne)
      ** En sortie, on a la date suivie d'un espace puis le nom de fichier

    • sort : on trie les lignes dans l'ordre alphanumérique :)

    • cut -d' ' -f2- :
      ** -d' ' : Le délimiteur de champs est l'espace
      ** -f2- : Garder tous les champs à partir du second

  • # sed ?

    Posté par . Évalué à 3.

    sed "s/\(.*\)\(_[0-9]\{8\}_[0-9]\{6\}\.[A-Za-z]\{3\}\)$/\2\1\2/" foo.txt | sort | cut -c 21-
    
    

    je copie-colle les 20 caractères de la fin au début pour pouvoir trier et ensuite je les revire…

  • # Perl uniligne sans parser ls

    Posté par . Évalué à 1. Dernière modification le 04/10/12 à 17:49.

    Dans un shell :

    printf '%s\n' * | 
        perl -lane '
            END{
                for (sort {$a<=>$b} keys(%hash)) {
                    print $hash{$_};
                }
            }
    
            $hash{$2} = $1 if /^(\d+\D+(\d{8})_\d+\.\w+)$/;
        '
    
    
  • # Trop fort !

    Posté par . Évalué à 1.

    @ Pierre :
    Excellent, ça marche du feu de Dieu !
    La syntaxe que je découvre c'est le 'NF-1' et '$(NF-1)'

    @ Aedrin :
    Très bien aussi, mais un peu moins compréhensible à la relecture…

    Merci beaucoup.

    • [^] # Re: Trop fort !

      Posté par . Évalué à 2.

      Nouvelle version qui correspond plus à ce que tu demande (nomenclature des fichiers) :

      printf '%s\n' * |
          perl -lane '
              END{
                  for (sort {$a<=>$b} keys(%hash)) {
                      print $hash{$_};
                  }
              }
      
              $hash{$2} = $1 if /(.*?(\d{8})_\d{6}\.\w+)$/;
          '
      
      

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.