Récupère tous les noms de files avec un nombre spécifique de caractères

Je veux changer tous les noms de files ils ont la longueur exacte de 16 caractères (numbers et lettres minuscules). J'ai essayé [0-9a-z]{16} et [0-9a-z]\{16\} pour l'espace réservé regX dans l'extrait suivant, mais cela ne fonctionne pas.

 for file in <regX> do mv "$file" "${file}.txt" done 

Avec extglob

 shopt -s extglob for file in +([0-9a-z]) do [[ ${#file} == 16 ]] && echo mv "$file" "${file}.txt" done 
  • +([0-9a-z]) signifie un ou plusieurs des caractères [0-9a-z]
  • ${#file} donne la longueur du nom de file
  • echo est pour la course à sec, retirer une fois que tout va bien

Les motifs de globulation de Shell ne sont pas des expressions régulières . Ils peuvent ressembler, mais ils fonctionnent différemment à certains égards.

L'expression régulière [0-9a-z]{16} correspond à une string contenant 16 caractères de la plage de caractères mentionnée (la string contenant la correspondance peut être plus longue).

Le model de globulation de l'obus équivalent serait quelque chose comme

 *[0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z]* 

Ceci est dû au fait

  1. Les patterns de globbing ne supportent pas les modificateurs qui disent "répéter les N fois précédentes".
  2. Les templates de gloutons sont ancrés par défaut au début et à la fin. C'est pourquoi j'ai inséré * au début et à la fin du motif. A * correspond à n'importe quel nombre de n'importe quel caractère. Retirez-les si vous voulez faire correspondre exactement 16 caractères.

Vous pouvez créer une string de 16 [0-9a-z] utilisant Perl:

 $ pattern="$( perl -e 'print "[0-9a-z]" x 16' )" 

Avec bash , vous pouvez choisir d'itérer sur tous les noms dans le directory courant, puis tester si les noms correspondent à votre expression régulière:

 for name in *; do if [[ -f "$name" ]] && [[ "$name" =~ ^[0-9a-z]{16}$ ]]; then echo mv "$name" "$name.txt" fi done 

Retirez l' echo une fois que vous savez qu'il fait la bonne chose.

Notez que j'ai ancré le motif afin que les noms plus longs ne correspondent pas. Je m'assure également, avec le test -f , que les noms que nous obtenons ne sont en fait que ceux des files normaux.

Si vous avez renommé perl ( rename sur les systèmes Debian, perl-rename sur les autres), vous pouvez faire:

 perl-rename -n 's/^[0-9a-z]{16}$/$&.txt/' * 

Si c'est ce que vous voulez, supprimez le -n pour qu'il renomme réellement les files. La syntaxe de perl-rename est une command perl. Ici, nous utilisons l'opérateur de substitution ( s/from/to/ ) qui replacea from with. Le dans de ce cas est votre regex et le est la variable spéciale $& qui signifie "tout ce qui a été apparié", plus l'extension .txt .


Pour faire cela avec un shell glob (utilisez l' approche de @ Kusalananda ou @ Sundeep , c'est juste pour l'accomplissement):

 for f in [0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z]; do mv -- "$f" "$f".txt done 

Avec GNU find :

 find . -regextype posix-extended -regex '.*/[0-9a-z]{16}' -exec mv {} {}".txt" \; 
 L16=$(csh -c 'repeat 16 echo -n "?"') find . -name "$L16" ! -name '*[!0-9a-z]*' -exec sh -c ' mv "$1" "$1.txt" ' {} {} \;