Comment renommer l'extension pour un tas de fichiers?

480

Dans un répertoire, j'ai un tas de *.htmlfichiers. Je voudrais tous les renommer*.txt

Comment puis je faire ça? J'utilise le shell bash.

bmw0128
la source

Réponses:

382

Pour une meilleure solution (avec uniquement la fonctionnalité bash, par opposition aux appels externes), consultez l' une des autres réponses .


Ce qui suit ferait et n'exige pas que le système ait le renameprogramme (bien que vous l'ayez le plus souvent sur un système):

for file in *.html; do
    mv "$file" "$(basename "$file" .html).txt"
done

EDIT: Comme indiqué dans les commentaires, cela ne fonctionne pas pour les noms de fichiers avec des espaces sans citations appropriées (maintenant ajoutés ci-dessus). Lorsque vous travaillez uniquement sur vos propres fichiers dont vous savez qu'ils n'ont pas d'espace dans les noms de fichiers, cela fonctionnera, mais chaque fois que vous écrivez quelque chose qui peut être réutilisé ultérieurement, ne sautez pas les citations appropriées.

Mikael Auno
la source
47
Une alternative, sans nom de base et avec guillemets: mv "$ {file}" "$ {file /%. Html / .txt}" (voir man bash, Expansion des paramètres pour plus de détails)
Rodrigo Queiro
7
Bien seulement si les fichiers sont tous dans le répertoire courant, bien sûr, car le nom de base supprime la partie du chemin. Juste un "méfiez-vous"!
Jonathan Leffler
6
Cette solution est mauvaise, non seulement parce qu'elle est lente, mais parce qu'elle ne fonctionne pas avec les noms de fichiers contenant des espaces. Vous devriez TOUJOURS faire une citation appropriée dans les scripts bash. mv "$ file" "$ (nom de base" $ file ".html)". txt serait bien mieux. Mais encore, mv "$ files" "$ {files% .html} .txt" est bien meilleur.
Balázs Pozsár
8
dans les fenêtres que vous venez de faireren *.a *.b
Muhammad Umer
2
Au minimum, utilisez la $()syntaxe backtick héritée spécifiée par POSIX . Améliore la lisibilité et rend la syntaxe beaucoup moins ambiguë lorsque vous avez des caractères qui devraient être échappés par une barre oblique inverse pour être littéraux dans la substitution de commande avec cette dernière.
Charles Duffy
669

Si vous utilisez bash, vous n'avez pas besoin de commandes externes comme sed, nom de base, renommer, expr, etc.

for file in *.html
do
  mv "$file" "${file%.html}.txt"
done
ghostdog74
la source
12
Et si vous ne connaissez pas l'extension de fichier que vous pouvez utiliser "${file%.*}.txt", mais cela pourrait être dangereux pour les fichiers sans extension.
Jess
1
Remarque à tous ceux qui ont du mal à faire fonctionner cela comme moi: notez qu'il n'y a pas $à l'intérieur des accolades!
doug65536
5
J'ai besoin d'un moyen de mettre en favoris / mettre en signet cette réponse en permanence, je ne me souviens plus de la syntaxe exacte et je
finis par googler
7
@danip La construction percent-sign-within-bracket supprime les caractères de la fin. Il existe également une construction de hachage entre parenthèses qui supprime les caractères du début. Vérifiez-le: tldp.org/LDP/abs/html/parameter-substitution.html#PSUB2
4
Une autre réponse d'échange de pile (que je ne trouve pas!) A suggéré cela, mais aussi en utilisant --"l'opérateur": mv - "$ file" "$ {file% .html} .txt" Cet opérateur empêche les noms de fichiers commençant par un '-' d'être analysé par mv comme arguments.
rcreswick
191
rename 's/\.html$/\.txt/' *.html

fait exactement ce que vous voulez.

ambre
la source
Je ne pense pas que vous puissiez utiliser un regex littéral dans bash comme vous le suggérez - quel shell utilisez-vous?
DaveR
1
j'utilise
Voici la page de manuel pour la version de renommer sur Ubuntu: unixhelp.ed.ac.uk/CGI/man-cgi?rename
Amber
renommer est une commande sur certains systèmes. J'ai un script Perl (à l'origine du premier livre Camel) qui fait le travail. Il existe également un programme GNU du même nom qui fait à peu près le même travail. Mon Mac n'a pas de commande «renommer» fournie par le système - ou ce n'est pas sur mon PATH (qui est modérément complet).
Jonathan Leffler
Il existe une formule de changement de nom dans Homebrew.
revprez
112

Cela a fonctionné pour moi sur OSX de .txt à .txt_bak

find . -name '*.txt' -exec sh -c 'mv "$0" "${0%.txt}.txt_bak"' {} \;
Steven Lizarazo
la source
4
Fonctionne très bien sous Linux aussi.
Diziet
C'est d'ailleurs le point, mais pour aller de .txtchez .txt_bakvous il suffit de concaténer _bak;)
corwin.amber
3
C'est bien pour renommer récursivement
leachryanb
Génial! (sous Ubuntu 16.04) Mon cas d'utilisation pratique, renommant tout .scssen .sass(après la conversion sur place…):find . -name '*.scss' -exec sh -c 'mv "$0" "${0%.scss}.sass"' {} \;
Frank Nocke
2
cela a fonctionné avec +6000 fichiers, renommer signalé "la liste d'arguments était trop longue"
Tony Cronin
94

Vous souhaitez utiliser rename:

rename -S .html .txt *.html

Cela fait exactement ce que vous voulez - cela changera l'extension de .htmlà .txtpour tous les fichiers correspondants *.html.

Remarque: Greg Hewgill souligne correctement qu'il ne s'agit pas d'une fonction bash intégrée; et est une commande Linux séparée. Si vous avez juste besoin de quelque chose sur Linux, cela devrait fonctionner correctement; si vous avez besoin de quelque chose de plus multiplateforme, jetez un œil à l'une des autres réponses.

DaveR
la source
7
Bien que ce soit une bonne solution, le renameprogramme n'est pas lié à bashet n'est pas non plus disponible sur toutes les plateformes. Je ne l'ai vu que sous Linux.
Greg Hewgill
15
"$ rename .html .txt * .html" entraîne ... une erreur de syntaxe à (eval 1) ligne 1, près de "."
Amber
8
La syntaxe correcte est rename -S .html .text *.html-Sest synonyme de--subst-all
Marek Sebera
8
brew install rename
Nick
4
@GregHewgill rename est disponible pour Mac OS avec HomeBrew
CodeBrauer
36

Sur un Mac ...

  1. Installez renommer si vous n'avez pas:brew install rename
  2. rename -S .html .txt *.html
izilotti
la source
15

Pour les utilisateurs d'Ubuntu:

rename 's/\.html$/\.txt/' *.html
Bheru Lal Lohar
la source
Ce n'est pas récursif, mais cela a fonctionné pour moi sur Ubuntu 14.04.
Max Wallace
9

C'est la solution la plus simple que j'ai trouvée qui fonctionne sur OSX et Linux, et elle fonctionne aussi très bien avec git!

find . -name "*.js" -exec bash -c 'mv "$1" "${1%.js}".tsx' - '{}' \;

et avec git:

find . -name "*.js" -exec bash -c 'git mv "$1" "${1%.js}".tsx' - '{}' \;

bdombro
la source
8

Voici un exemple de la commande renommer:

rename -n s/\.htm$/\.html/’ *.htm

Le -n signifie qu'il s'agit d'un test et ne modifiera en fait aucun fichier. Il vous montrera une liste de fichiers qui seraient renommés si vous supprimiez le -n. Dans le cas ci-dessus, il convertira tous les fichiers du répertoire actuel à partir d'une extension de fichier de .htm en .html.

Si la sortie du test ci-dessus semblait correcte, vous pouvez exécuter la version finale:

rename -v s/\.htm$/\.html/’ *.htm

Le -v est facultatif, mais c'est une bonne idée de l'inclure car c'est le seul enregistrement que vous aurez des modifications qui ont été apportées par la commande renommer comme indiqué dans l'exemple de sortie ci-dessous:

$ rename -v 's/\.htm$/\.html/' *.htm
3.htm renamed as 3.html
4.htm renamed as 4.html
5.htm renamed as 5.html

La partie délicate au milieu est une substitution Perl avec des expressions régulières, mise en évidence ci-dessous:

rename -v s/\.htm$/\.html/’ *.htm
AA
la source
6

Cette question mentionne explicitement Bash, mais s'il vous arrive d'avoir ZSH disponible, c'est assez simple:

zmv '(*).*' '$1.txt'

Si vous obtenez, zsh: command not found: zmvlancez simplement:

autoload -U zmv

Et puis réessayez.

Merci à cet article original pour l'astuce sur zmv.

Michael Leonard
la source
4

Après l'exploration du site Web de quelqu'un d'autre, je me suis retrouvé avec des milliers de fichiers sans l'extension .html, dans une large arborescence de sous-répertoires.

Pour les renommer tous d'un seul coup, à l'exception des fichiers ayant déjà une extension .html (la plupart d'entre eux n'en avaient pas du tout), cela a fonctionné pour moi:

cd wwwroot
find . -xtype f \! -iname *.html   -exec mv -iv "{}"  "{}.html"  \;  # batch rename files to append .html suffix IF MISSING

Dans le cas de l'OP, je pourrais modifier légèrement cela, pour ne renommer que les fichiers * .txt, comme ceci:

find . -xtype f  -iname *.txt   -exec filename="{}"  mv -iv ${filename%.*}.{txt,html}  \; 

En panne (hammertime!):

-iname * .txt
- Signifie que seuls les fichiers se terminant déjà par .txt

mv -iv "{}. {txt, html}" - Lorsque find passe un {} comme nom de fichier, $ {filename%. *} extrait son nom de base sans aucune extension pour former les paramètres à mv . bash prend le {txt, html} pour le réécrire en deux paramètres afin que la commande finale s'exécute comme:mv -iv "filename.txt" "filename.html"

Correction nécessaire cependant: gérer les espaces dans les noms de fichiers

Marcos
la source
4

La commandemmv semble effectuer cette tâche très efficacement sur un grand nombre de fichiers (des dizaines de milliers en une seconde). Par exemple, pour renommer tous les .xmlfichiers en .htmlfichiers, utilisez ceci:

mmv ";*.xml" "#1#2.html"

le ;correspondra au chemin, le *correspondra au nom de fichier, et ceux-ci sont appelés #1et#2 dans le nom de remplacement.

Les réponses basées sur execou les canaux étaient trop lentes ou ont échoué sur un très grand nombre de fichiers.

Roko Mijic
la source
3

Essaye ça

rename .html .txt *.html 

usage:

rename [find] [replace_with] [criteria]
P Sreedhar
la source
3

Un peu tard pour la fête. Vous pouvez le faire avec xargs:

ls *.html | xargs -I {} sh -c 'mv $1 `basename $1 .html`.txt' - {}

Ou si tous vos fichiers sont dans un dossier

ls folder/*.html | xargs -I {} sh -c 'mv $1 folder/`basename $1 .html`.txt' - {}
esp
la source
3
Non, ne pas analyserls . Cette commande est ridicule: elle utilise inutilement un glob avec ls, au lieu d'utiliser directement le glob. Cela rompra avec les noms de fichiers contenant des espaces, des guillemets et (en raison du manque de guillemets) des caractères globaux.
gniourf_gniourf
Pour info, votre article lié contient une note mise à jour qui dit que le nouveau LS "correctement" échappe les fichiers "s'ils sont imprimés sur le terminal." Votre point est cependant une bonne règle de base.
Katastic Voyage
3

C'est un bon moyen de modifier plusieurs extensions à la fois:

for fname in *.{mp4,avi}
do
   mv -v "$fname" "${fname%.???}.mkv"
done

Remarque: faites attention à ce que la taille de l'extension soit la même (la ???)

Nick De Greek
la source
2

Nice & simple!

find . -iname *.html  -exec mv {} "$(basename {} .html).text"  \;
Deano
la source
2

Si vous préférez PERL, il existe un court script PERL (écrit à l'origine par Larry Wall, le créateur de PERL) qui fera exactement ce que vous voulez ici: tips.webdesign10.com/files/rename.pl.txt .

Pour votre exemple, ce qui suit devrait faire l'affaire:

rename.pl 's/html/txt/' *.html
dudusan
la source
2
Cette question a déjà été répondue et acceptée depuis longtemps et il ne semble pas que votre réponse apporte plus que ce qui a déjà été dit.
ChristopheLec
1
+1 puisqu'il s'agissait d'un script Larry Wall (modifié par Robin Barker). La dernière URL disponible est la suivante: tips.webdesign10.com/files/rename.pl.txt
loretoparisi
1

De la même manière que ce qui a été suggéré auparavant, voici comment je l'ai fait:

find . -name '*OldText*' -exec sh -c 'mv "$0" "${0/OldText/NewText}"' {} \;

J'ai d'abord validé avec

find . -name '*OldText*' -exec sh -c 'echo mv "$0" "${0/OldText/NewText}"' {} \;
Carl Bosch
la source
1

Une ligne, pas de boucles:

ls -1 | xargs -L 1 -I {} bash -c 'mv $1 "${1%.*}.txt"' _ {}

Exemple:

$ ls
60acbc4d-3a75-4090-85ad-b7d027df8145.json  ac8453e2-0d82-4d43-b80e-205edb754700.json
$ ls -1 | xargs -L 1 -I {} bash -c 'mv $1 "${1%.*}.txt"' _ {}
$ ls
60acbc4d-3a75-4090-85ad-b7d027df8145.txt  ac8453e2-0d82-4d43-b80e-205edb754700.txt
Christian Bongiorno
la source
+1 pour afficher une méthode bash uniquement qui ne dépend pas de la correspondance exacte avec l'extension existante. Cela fonctionne pour n'importe quelle extension d'entrée, que ce soit 3 caractères de long ou 4 caractères de long ou plus
Ciprian Tomoiagă
0

Malheureusement, ce n'est pas trivial de le faire de manière portable. Vous avez probablement besoin d'un peu de magie expr.

for file in *.html; do echo mv -- "$file" "$(expr "$file" : '\(.*\)\.html').txt"; done

Supprimez l'écho une fois que vous êtes satisfait, il fait ce que vous voulez.

Edit: basename est probablement un peu plus lisible pour ce cas particulier, bien qu'il exprsoit plus flexible en général.

CB Bailey
la source
Bien que ce ne soit pas la meilleure réponse à la question, c'était pour moi! J'avais besoin d'un moyen de renommer uniquement en chaîne un chemin entier, pas seulement un nom de fichier. Merci d'avoir posté!
beignet
0

Voici ce que j'ai utilisé pour renommer des .edgefichiers.blade.php

for file in *.edge; do     mv "$file" "$(basename "$file" .edge).blade.php"; done

Fonctionne comme un charme.

Nixon Kosgei
la source
0

Vous pouvez également créer une fonction dans Bash, l'ajouter .bashrcou quelque chose, puis l'utiliser où vous le souhaitez.

change-ext() {
    for file in *.$1; do mv "$file" "$(basename "$file" .$1).$2"; done
}

Usage:

change-ext css scss

Source de code en fonction: https://stackoverflow.com/a/1224786/6732111

J Kluseczka
la source
0

Renommez les extensions de fichier pour tous les fichiers du répertoire et des sous-répertoires actuels sans aucun autre package (utilisez uniquement le script shell):

  1. Créez un script shell rename.shsous le répertoire courant avec le code suivant:

    #!/bin/bash
    
    for file in $(find . -name "*$1"); do
      mv "$file" "${file%$1}$2"
    done
  2. Exécutez-le ./rename.sh .old .new.

    Par exemple. ./rename.sh .html .txt

Neo Liu
la source