J'essaie de mettre toutes mes extensions en minuscule, peu importe ce que c'est. Jusqu'à présent, d'après ce que j'ai vu, vous devez spécifier quelles extensions de fichier vous souhaitez convertir en minuscules. Cependant, je veux juste tout mettre en minuscule après le premier dernier point .
dans le nom.
Comment puis-je faire cela dans bash
?
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 s’appliquera aux noms de fichiers contenant des nouvelles lignes. Mais supporte-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 en cours (.
) qui ont la période .
dans leur 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 minuscule (cela rend 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 la variable a
.
Si quelque chose a été modifié [ "$a" != "$0" ]
, renommez le fichier mv "$0" "$a"
.
Le nom du fichier en cours de traitement ({}
) est passé à sh -c
en tant qu'argument supplémentaire et apparaît à l'intérieur de la ligne de commande sous la forme $0
. Le script est sécurisé car, dans ce cas, le shell utilise {} comme donnée, pas comme une partie de code, comme quand il est spécifié directement dans la ligne de commande. (Je remercie @gniourf_gniourf de 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 le sera exécuté.
While-version
Version du script plus claire, mais un peu plus longue:
find . -name '*.*' | while IFS= read -r f
do
a=$(echo "$f" | sed -r "s/([^.]*)\$/\L\1/");
[ "$a" != "$f" ] && mv "$f" "$a"
done
Cela se casse toujours pour les noms de fichiers contenant des nouvelles lignes. Pour résoudre ce problème, vous devez disposer d'une find
prenant en charge -print0
(comme GNU find
) et de Bash (afin que read
prenne en charge le commutateur de délimiteur -d
):
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 se produit toujours pour les fichiers contenant des nouvelles lignes (car ils seront absorbés par le sous-shell a=$(...)
. Si vous vraiment voulez une méthode infaillible (et vous devriez!), Avec une version récente de Bash (Bash≥4.0) supporte l'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 dans un find
aller (retour à la solution originale avec quelques corrections qui le rend 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épertoire sont renommés avant les noms de fichier. Si vous souhaitez également renommer des répertoires (et des liens, des tuyaux, 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 faire valoir qu'il n'est pas efficace de générer un processus bash
pour chaque fichier trouvé. C'est correct, et la version précédente de la boucle serait alors meilleure.
J'ai eu du succès avec cette commande.
rename JPG jpg *.JPG
Où rename
est une commande qui demande au shell de renommer chaque occurrence de JPG
en jpg
dans le dossier actuel avec tous les noms de fichiers ayant l'extension JPG
.
Si vous voyez que les mots clés "JPG" ne sont pas autorisés alors que "subs strict" est utilisé à la première ligne (eval 1) avec cette approche, essayez:
rename 's/\.JPG$/.jpg/' *.JPG
Eh bien, vous pouvez utiliser cet extrait comme base de toute alternative dont vous avez besoin:
#!/bin/bash
# lowerext.sh
while read f; do
if [[ "$f" = *.* ]]; then
# Extract the basename
b="${f%.*}"
# Extract the extension
x="${f##*.}"
# Convert the extension to lower case
# Note: this only works in recent versions of Bash
l="${x,,}"
if [[ "$x" != "$l" ]]; then
mv "$f" "$b.$l"
fi
else
continue
fi
done
Ensuite, il vous suffit de créer une liste des fichiers que vous devez renommer en son entrée standard. Par exemple. pour tous les fichiers du répertoire en cours et de tout sous-répertoire:
find -type f | lowerext.sh
Une petite optimisation:
find -type f -name '*.*' | lowerext.sh
Vous devrez être plus précis si vous avez besoin d'une réponse plus concrète que celle-ci ...
Cela fera le travail de votre '.mp3 - mais seulement dans le répertoire de travail - mais est capable de consommer des noms de fichiers avec des espaces:
for f in *.[mM][pP]3; do mv "$f" "${f%.*}.mp3"; done
Correction:
for f in *.[mM][pP]3; do [[ "$f" =~ \.mp3$ ]] || mv "$f" "${f%.*}.mp3"; done
Si vous avez installé mmv
(= déplacer plusieurs fichiers) et que vos noms de fichier contiennent au plus un point, vous pouvez utiliser
mmv -v "*.*" "#1.#l2"
Il n'a pas plus d'un point à droite (puisque l'algo correspondant pour *
n'est pas glouton dans mmv
), cependant, il gère correctement ()
et '
. Exemple:
$ mmv -v "*.*" "#1.#l2"
FOO.BAR.MP3 -> FOO.bar.mp3 : done
foo bar 'baz' (CD 1).MP3 -> foo bar 'baz' (CD 1).mp3 : done
Pas parfait, mais beaucoup plus facile à utiliser et à retenir que tous les trucs find/exec/sed
.
récursivement pour tous une solution fine:
find -name '*.JPG' | sed 's/\(.*\)\.JPG/mv "\1.JPG" "\1.jpg"/' |sh
Ce qui précède renomme récursivement les fichiers portant l’extension "JPG" en fichiers portant l’extension "jpg"
Si vous utilisez ZSH:
zmv '(*).(*)' '$1.$2:l'
Si vous obtenez zsh: command not found: zmv
, lancez simplement:
autoload -U zmv
Et puis réessayez.
Merci à cet article article original pour l’information sur zmv et la documentation ZSH pour la syntaxe de substitution minuscule/majuscule.
Si vous avez installé JDK, vous pouvez simplement compiler les éléments suivants:
import Java.io.File;
public class FileRename {
public static void main(String[] args) {
long numFilesChanged = 0;
long numFilesNotChanged = 0;
try {
final File directory = new File(".");
final File[] listOfFiles = directory.listFiles();
for (int i = 0; i < listOfFiles.length; i++) {
if (!listOfFiles[i].isFile()) {
continue;
}
final File fileToRename = listOfFiles[i];
final String filename = fileToRename.getName();
final String woExtension = filename.substring(0, filename.lastIndexOf('.'));
final String extension = filename.substring(filename.lastIndexOf('.'));
if (extension.toLowerCase().equals(extension)) {
numFilesNotChanged++;
} else {
numFilesChanged++;
fileToRename.renameTo(new File(woExtension + extension.toLowerCase()));
}
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Changed: " + numFilesChanged);
System.out.println("Not changed:" + numFilesNotChanged);
}
}
et courir.
Si vous n'avez pas installé JDK mais Java, compilez-le à l'aide d'un compilateur Java en ligne tel que: https://www.compilejava.net/ et placez simplement le fichier .class obtenu dans le dossier où vous voulez renommez vos fichiers et exécutez: Java FileRename
.
N'hésitez pas à me contacter si vous n'êtes pas familier avec Java ou si vous avez besoin d'aide pour la compilation et/ou l'exécution.
Si vous ne vous intéressez qu'à certaines extensions de fichier, telles que la conversion de toutes les extensions "JPG" en majuscules en minuscules "jpg", vous pouvez utiliser l'utilitaire de ligne de commande rename like. CD dans le répertoire que vous souhaitez modifier. ensuite
rename -n 's/\.JPG$/\.jpg/' *
Utilisez l'option -n pour tester ce qui va changer, puis utilisez-le sans résultat
rename 's/\.JPG$/\.jpg/' *