GNU/Linux >> Tutoriels Linux >  >> Linux

Convertir toutes les extensions de fichiers en minuscules

J'ai réussi avec cette commande.

rename JPG jpg *.JPG

rename est une commande qui indique au shell de renommer chaque occurrence de JPG à jpg dans le dossier courant avec tous les noms de fichiers ayant l'extension JPG .

Si vous voyez que Bareword "JPG" n'est pas autorisé alors que "strict subs" est utilisé à (eval 1) ligne 1 avec cette approche, essayez :

rename 's/\.JPG$/.jpg/' *.JPG

Solution

Vous pouvez résoudre la tâche en une seule ligne :

find . -name '*.*' -exec sh -c '
  a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/");
  [ "$a" != "$0" ] && mv "$0" "$a" ' {} \;

Remarque :cela cassera pour les noms de fichiers qui contiennent des retours à la ligne. Mais supportez-moi pour l'instant.

Exemple d'utilisation

$ mkdir C; touch 1.TXT a.TXT B.TXT C/D.TXT
$ find .
.
./C
./C/D.TXT
./1.TXT
./a.TXT
./B.TXT

$ find . -name '*.*' -exec sh -c 'a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/"); [ "$a" != "$0" ] && mv "$0" "$a" ' {} \;

$ find .
.
./C
./C/D.txt
./a.txt
./B.txt
./1.txt

Explication

Vous trouvez tous les fichiers dans le répertoire courant (. ) qui ont la période . en son nom (-name '*.*' ) et exécutez la commande pour chaque fichier :

a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/");
[ "$a" != "$0" ] && mv "{}" "$a"

Cette commande signifie :essayez de convertir l'extension de fichier en minuscules (ce qui fait sed ):

$ echo 1.txt | sed -r "s/([^.]*)\$/\L\1/"
1.txt
$ echo 2.TXT | sed -r "s/([^.]*)\$/\L\1/"
2.txt

et enregistrez le résultat dans le a variables.

Si quelque chose a été changé [ "$a" != "$0" ] , renommer le fichier mv "$0" "$a" .

Le nom du fichier en cours de traitement ({} ) passé à sh -c comme argument supplémentaire et il est vu à l'intérieur de la ligne de commande comme $0 .Cela rend le script sûr, car dans ce cas, le shell prend {} comme une donnée, et non comme une partie de code, comme lorsqu'il est spécifié directement dans la ligne de commande.(Je remercie @gniourf_gniourf pour m'avoir signalé ce problème très important ).

Comme vous pouvez le voir, si vous utilisez {} directement dans le script, il est possible d'avoir des injections de shell dans les noms de fichiers, quelque chose comme :

; rm -rf * ;

Dans ce cas, l'injection sera considérée par le shell comme faisant partie du code et elle sera exécutée.

While-version

Version plus claire, mais un peu plus longue, du script :

find . -name '*.*' | while IFS= read -r f
do
  a=$(echo "$f" | sed -r "s/([^.]*)\$/\L\1/");
  [ "$a" != "$f" ] && mv "$f" "$a"
done

Cela casse toujours pour les noms de fichiers contenant des retours à la ligne. Pour résoudre ce problème, vous devez disposer d'un find qui prend en charge -print0 (comme GNU find ) et Bash (pour que read prend en charge le -d commutateur de délimiteur) :

find . -name '*.*' -print0 | while IFS= read -r -d '' f
do
  a=$(echo "$f" | sed -r "s/([^.]*)\$/\L\1/");
  [ "$a" != "$f" ] && mv "$f" "$a"
done

Cela casse toujours pour les fichiers qui contiennent des retours à la ligne (car ils seront absorbés par le a=$(...) sous-coque. Si vous vraiment voulez une méthode infaillible (et vous devriez !), avec une version récente de Bash (Bash≥4.0) qui supporte le ,, expansion des paramètres voici la solution ultime :

find . -name '*.*' -print0 | while IFS= read -r -d '' f
do
  base=${f%.*}
  ext=${f##*.}
  a=$base.${ext,,}
  [ "$a" != "$f" ] && mv -- "$f" "$a"
done

Retour à la solution d'origine

Ou en un find go (retour à la solution d'origine avec quelques correctifs qui la rendent vraiment infaillible):

find . -name '*.*' -type f -exec bash -c 'base=${0%.*} ext=${0##*.} a=$base.${ext,,}; [ "$a" != "$0" ] && mv -- "$0" "$a"' {} \;

J'ai ajouté -type f afin que seuls les fichiers normaux soient renommés. Sans cela, vous pourriez toujours avoir des problèmes si les noms de répertoires sont renommés avant les noms de fichiers. Si vous souhaitez également renommer des répertoires (et des liens, des canaux, etc.), vous devez utiliser -depth :

find . -depth -name '*.*' -type f -exec bash -c 'base=${0%.*} ext=${0##*.} a=$base.${ext,,}; [ "$a" != "$0" ] && mv -- "$0" "$a"' {} \;

de sorte que find effectue une recherche en profondeur d'abord.

Vous pouvez dire qu'il n'est pas efficace de générer un bash processus pour chaque fichier trouvé. C'est exact, et la version précédente de la boucle serait alors meilleure.


Ceci est plus court mais plus général, combiné à partir de la réponse des autres :

rename 's/\.([^.]+)$/.\L$1/' *

Simulation

Pour la simulation, utilisez -n , soit rename -n 's/\.([^.]+)$/.\L$1/' * . De cette façon, vous pouvez voir ce qui sera modifié avant que les modifications réelles ne soient effectuées. Exemple de sortie :

Happy.Family.GATHERING.JPG renamed as Happy.Family.GATHERING.jpg
Hero_from_The_Land_Across_the_River.JPG renamed as Hero_from_The_Land_Across_the_River.jpg
rAnD0m.jPg1 renamed as rAnD0m.jpg1

Brève explication sur la syntaxe

  • La syntaxe est rename OPTIONS 's/WHAT_TO_FIND_IN_THE_NAME/THE_REPLACEMENT/' FILENAMES
  • \.([^.]+)$ signifie une séquence de tout sauf un point ([^.] ) à la fin de la chaîne ($ ), après le point (\. )
  • .\L$1 signifie point (\. ) suivi de minuscules (\L ) de 1 groupe ($1 )
  • Le premier groupe dans ce cas est l'extension ([^.]+ )
  • Vous feriez mieux d'utiliser l'apostrophe ' au lieu des guillemets doubles " pour envelopper la regex pour éviter l'expansion du shell

Linux
  1. Comment nettoyer les extensions de fichiers ?

  2. Afficher tout le fichier jusqu'au match ?

  3. Écrire dans le fichier .txt ?

  4. Convertir .txt en .csv dans le shell

  5. Obtenir toutes les extensions et leur nombre de fichiers respectifs dans un répertoire

Comment supprimer tous les fichiers d'un dossier sauf un fichier spécifique sous Linux

Comment convertir un fichier Windows en un fichier UNIX

Rediriger toutes les sorties vers un fichier à l'aide de Bash sous Linux ?

Modification de toutes les extensions de fichier dans un dossier à l'aide de la CLI sous Linux

Comment convertir tar.bz2 en tar.gz ?

format de fichier de mot de passe ldapsearch