Comment extraire des éléments spécifiques d'un nom de file?

J'ai un tas de files dans le format suivant:

2014-11-19.8.ext 2014-11-26.1.ext 2014-11-26.2.blah.ext 2014-11-26_3.ext 2014-11-26.4.stuff_here.ext 2014-12-03.1. could be anything.ext 2014-12-032b.ext 2014-11-26 613 adva.ext 

Mon but est de parcourir la list complète des files et de prendre le format de date de YYYY-MM-DD et de le stocker dans une variable au format YYYYMMDD pour traitement ultérieur (dans mon cas, il sera poussé dans une command touch ).

Donc normalement je ferais correspondre cette expression régulière: (\d{4})-(\d{2})-(\d{2}).*

Et puis utiliser $1$2$3 pour get mon model désiré, mais je ne suis pas sûr de savoir comment faire dans bash / zsh .

Comment cela peut-il être fait dans un script shell en tant que tel?

Utilisation de l' expansion des parameters

 $ touch 2014-11-19.8.ext 2014-11-26.1.ext $ for f in *.ext; do d="${f:0:4}${f:5:2}${f:8:2}"; echo "$d"; done 20141119 20141126 
  • ${f:0:4} signifie 4 caractères commençant par l'index 0 et f nom de la variable
  • replace echo "$d" par votre code

Pour mettre en boucle chaque file du directory courant et comparer leurs noms de files au model désiré, définissez une variable contenant les pièces de la date

 for f in * do [[ $f =~ ^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])(.*) ]] && yourvar="${BASH_REMATCH[1]}${BASH_REMATCH[2]}${BASH_REMATCH[3]}" done 

Cela utilise bash [[ possibilité d'utiliser la correspondance d'expressions régulières pour placer les pièces de date dans le tableau BASH_REMATCH.

Vous pouvez le faire de façon interactive en utilisant GNU sed :

 $ sed 's/^\([0-9]\{4\}\)-\([0-9]\{2\}\)-\([0-9]\{2\}.*\)/\1\2\3/g' stuff.txt 

Pour plusieurs files (si dans le même directory et aucun autre file considéré dans le directory):

 for file in * do if [ -f "$file" ] then sed 's/^\([0-9]\{4\}\)-\([0-9]\{2\}\)-\([0-9]\{2\}\).*/\1\2\3/g' "$file" fi done 

Voici une façon zsh de faire cela, sans loops:

 autoload -U zmv zmv -n '([0-9](#c4))-([0-9](#c2))-([0-9](#c2))(*)' '$1$2$3$4' 
  • [0-9](#c4) signifie tout chiffre répété 4 fois
  • $1$2 réfèrent à la parenthèse précédemment utilisée
  • -n empêche l'exécution (printing uniquement), supprime ce drapeau si vous êtes satisfait du résultat

Comme zsh prend soin de globuler tous les cas de coin (espaces blancs, caractères spéciaux, etc.) doivent être pris en count automatiquement.

Si vous utilisez GNU Coreutils, vous avez ceci:

 $ date --date=2014-11-13 +"%Y%m%d" 20141113 

Toutefois:

 $ date --date=2014-11-130ABCJUNK +"%Y%m%d" date: invalid date '2014-11-130ABCJUNK' 

Ainsi, la tâche est beaucoup plus simple: extraire les dix premiers caractères de chaque nom de file YYYY-MM-DDetc pour get la date seule, puis passer à la date de reformatting.

Mais si nous sums sur GNU Coreutils, nous pouvons ignorer la command date car touch a exactement la même option --date=STRING .

 for file in * ; do date=${file%${file##??????????}} # chop all but first ten touch --date=$date -- "$file" done 

Mais pourquoi ce découpage de dix caractères dans le mode POSIX est-il portable alors que nous nous appuyons sur le touch de GNU Coreutils?

 for file in * ; do date=${file:0:10} touch --date=$date -- "$file" done 

Essayez la substitution de motif:

 ${parameter/pattern/ssortingng} 

paramètre est le nom de base du file. motif est un tiret. Dans ce / – replace le model globalement. string est vide, puisque vous voulez supprimer les tirets.

 mv "${f}" "${f//-/}" 

Caveat: Je n'ai pas eu ce travail avec le cas des espaces dans l'extension.