J'ai de nombreux fichiers avec .abc
et je veux les changer en .edefg
Comment faire cela en ligne de commande ?
J'ai un dossier racine avec de nombreux sous-dossiers, la solution devrait donc fonctionner de manière récursive.
J'ai de nombreux fichiers avec .abc
et je veux les changer en .edefg
Comment faire cela en ligne de commande ?
J'ai un dossier racine avec de nombreux sous-dossiers, la solution devrait donc fonctionner de manière récursive.
Une méthode portable (qui fonctionnera sur tout système compatible POSIX) :
find /the/path -depth -name "*.abc" -exec sh -c 'mv "$1" "${1%.abc}.edefg"' _ {} \;
En bash4, vous pouvez utiliser globstar pour obtenir des globs récursifs (**) :
shopt -s globstar
for file in /the/path/**/*.abc; do
mv "$file" "${file%.abc}.edefg"
done
Le (perl) rename
dans Ubuntu peut renommer des fichiers en utilisant la syntaxe des expressions régulières perl, que vous pouvez combiner avec globstar ou find
:
# Using globstar
shopt -s globstar
files=(/the/path/**/*.abc)
# Best to process the files in chunks to avoid exceeding the maximum argument
# length. 100 at a time is probably good enough.
# See http://mywiki.wooledge.org/BashFAQ/095
for ((i = 0; i < ${#files[@]}; i += 100)); do
rename 's/\.abc$/.edefg/' "${files[@]:i:100}"
done
# Using find:
find /the/path -depth -name "*.abc" -exec rename 's/\.abc$/.edefg/' {} +
Voir aussi http://mywiki.wooledge.org/BashFAQ/030
Un problème avec les renommages récursifs est que, quelle que soit la méthode utilisée pour localiser les fichiers, elle transmet l'ensemble du chemin d'accès à l'application rename
et pas seulement le nom du fichier. Il est donc difficile d'effectuer des renommages complexes dans des dossiers imbriqués.
J'utilise find
's -execdir
action pour résoudre ce problème. Si vous utilisez -execdir
au lieu de -exec
la commande spécifiée est exécutée à partir du sous-répertoire contenant le fichier correspondant. Ainsi, au lieu de passer le chemin complet à rename
il ne fait que passer ./filename
. Cela rend l'écriture de la regex beaucoup plus facile.
find /the/path -type f \
-name '*.abc' \
-execdir rename 's/\.\/(.+)\.abc$/version1_$1.abc/' '{}' \;
En détail :
-type f
signifie rechercher uniquement les fichiers, pas les répertoires-name '*.abc'
signifie que seuls les noms de fichiers se terminant par .abc sont pris en compte.'{}'
est l'espace réservé qui marque l'endroit où -execdir
insérera le chemin trouvé. Les guillemets simples sont nécessaires, pour lui permettre de gérer les noms de fichiers avec des espaces et des caractères Shell.-type
et -name
sont le caractère de continuation de ligne de bash. Je les utilise pour rendre cet exemple plus lisible, mais ils ne sont pas nécessaires si vous mettez votre commande sur une seule ligne.-execdir
est nécessaire. Elle est là pour échapper au point-virgule, qui termine la commande exécutée par -execdir
. Fun !Explication de la regex :
s/
début de la regex
\.\/
correspond au ./ de tête que -execdir passe dans. Utilisez \ pour échapper aux métacaractères . et / (note : cette partie varie en fonction de votre version de find
. Voir le commentaire de l'utilisateur @apollo)
(.+)
correspond au nom du fichier. Les parenthèses capturent la correspondance pour une utilisation ultérieure.
\.abc
échapper au point, correspondre à l'abc
$
ancrer la correspondance à la fin de la chaîne de caractères
/
marque la fin de la partie "match" de la regex, et le début de la partie "replace".
version1_
ajouter ce texte à chaque nom de fichier
$1
fait référence au nom de fichier existant, car nous l'avons capturé avec des parenthèses. Si vous utilisez plusieurs jeux de parenthèses dans la partie "match", vous pouvez y faire référence ici en utilisant $2, $3, etc.
.abc
le nouveau nom de fichier se terminera par .abc. Il n'est pas nécessaire d'échapper le métacaractère point ici dans la section "replace".
/
fin de la regex
Avant
tree --charset=ascii
|-- a_file.abc
|-- Another.abc
|-- Not_this.def
`-- dir1
`-- nested_file.abc
Après
tree --charset=ascii
|-- version1_a_file.abc
|-- version1_Another.abc
|-- Not_this.def
`-- dir1
`-- version1_nested_file.abc
Un conseil : rename
L'option -n de 's est utile. Elle fait un essai et vous montre les noms qu'elle va changer, mais ne fait aucun changement.
# Rename all *.txt to *.text
for f in *.txt; do
mv -- "$f" "${f%.txt}.text"
done
Voir également l'entrée sur la raison pour laquelle vous ne devriez pas analyser ls
.
Edit : si vous devez utiliser basename votre syntaxe serait :
for f in *.txt; do
mv -- "$f" "$(basename "$f" .txt).text"
done
https://unix.stackexchange.com/questions/19654/changing-extension-to-multiple-files
SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.