Comment puis-je utiliser renommer pour renommer récursivement tout en majuscules

11

Je voudrais renommer récursivement tous les fichiers et dossiers (sous-dossiers) en majuscules.

J'ai trouvé des scripts qui le feront en minuscules, mais je ne sais pas comment les changer, donc il le fera dans l'autre sens (de bas en haut).

Le script que j'ai trouvé et fonctionne en minuscule, mais je ne savais pas comment le modifier est:

rename 'y/A-Z/a-z/' *

Ça vient de man rename.

jnhghy - Alexandru Jantea
la source
Sans rien savoir de la commande renommer, je soupçonne que si vous essayez, rename 'y/a-z/A-Z/' *vous obtiendrez ce que vous voulez. Faites attention où vous le testez.
Warwick
ce n'est pas récursivement (parce que le premier n'était pas ...) mais ça marche. Je ne comprends pas pourquoi je n'ai pas réfléchi à ce mal :), alors!
jnhghy - Alexandru Jantea
Je pense que compte tenu de la qualité de la réponse de Gilles, il serait bon que vous acceptiez sa réponse de préférence à la mienne. Il est beaucoup plus complet que le mien et explique vos options (et comment tout cela fonctionne). Merci.
Warwick

Réponses:

8

Notez que vous utilisez le script Perl appelérename distribué par Debian et ses dérivés (Ubuntu, Mint,…). D'autres distributions Linux embarquent une commande complètement différente et considérablement moins utile appelée rename.

y/A-Z/a-z/se traduit chaque caractère dans la plage à Atravers Zdans le caractère correspondant dans la plage à atravers z, soit des lettres majuscules ASCII à la lettre minuscule correspondante. Pour effectuer la traduction opposée, utilisez y/a-z/A-Z/. Une autre façon d'écrire la même commande est rename '$_ = uc($_)' *ucest la fonction u pper c ase, et la renamecommande renomme les fichiers en fonction de la transformation effectuée dans la $_variable.

rename '…' *ne renomme que les fichiers du répertoire courant, car c'est ce qui *correspond. Les fichiers de points (les fichiers dont le nom commence par .) sont également ignorés.

Si vous souhaitez renommer les fichiers du répertoire en cours et des sous-répertoires de manière récursive, vous pouvez utiliser la findcommande pour parcourir le répertoire en cours de manière récursive. Il y a une difficulté ici: si vous appelez rename, cela renomme à la fois le répertoire et la partie nom de base. Si vous appelez renameun répertoire avant de rentrer dans it ( find -exec rename … {} \;), cela finddevient confus car il a trouvé un répertoire mais ce répertoire n'existe plus au moment où il essaie d'y descendre. Vous pouvez contourner ce en disant findà traverser un répertoire avant d' agir là - dessus, mais vous finissez par tenter de renommer foo/barpour , FOO/BARmais le répertoire FOOn'existe pas.

Un moyen simple d'éviter cette difficulté est de faire en sorte que la commande de changement de nom n'agisse que sur la partie du nom de base du chemin. L'expression régulière ([^/]*\Z)correspond à la dernière partie du chemin d'accès qui ne contient pas de /.

find . -depth -exec rename 's!([^/]*\Z)!uc($1)!e' {} +

Le shell zsh offre des fonctionnalités plus pratiques pour renommer - encore plus cryptique que Perl, mais plus tordu et souvent plus facile à composer.

La fonction zmvrenomme les fichiers en fonction des modèles. Exécutez autoload -U zmvune fois pour l'activer (mettez cette ligne dans votre .zshrc).

Dans le premier argument de zmv(le modèle à remplacer), vous pouvez utiliser les puissants modèles génériques de zsh . Dans le deuxième argument de zmv(le texte de remplacement), vous pouvez utiliser ses fonctions d' extension de paramètres , y compris les modificateurs d'historique .

zmv -w '**/*' '$1$2:u'

Explication:

  • -w - attribuer automatiquement des variables numériques à chaque motif générique
  • **/*- tous les fichiers dans les sous-répertoires, récursivement ( **/correspond à 0, 1 ou plusieurs niveaux de sous-répertoires)
  • $1 - la première variable numérique, correspondant ici à la partie répertoire de chaque chemin
  • $2:u- la deuxième variable numérique, correspondant ici à la partie du nom de base de chaque chemin, avec le :umodificateur pour convertir la valeur en majuscule

En prime, cela respecte les paramètres de l'environnement local.

Si vous n'êtes pas sûr d'une zmvcommande que vous avez écrite, vous pouvez passer l' -noption pour imprimer ce que la commande ferait et ne rien changer. Vérifiez la sortie et, si elle fait ce que vous voulez, réexécutez la commande sans -nréellement agir.

Gilles 'SO- arrête d'être méchant'
la source
5

Volé (avec une modification mineure) de Gilles post ici

find <DIR> -depth -type d -exec rename -n 's!/([^/]*/?)$!\U/$1!' {} +

Warwick
la source
Cela n'agit pas récursivement.
Gilles 'SO- arrête d'être méchant'
Vrai. J'aurais dû lire la question correctement. Je n'ai pas accès à la commande renommer, mais je pense que cela fonctionnera récursivement -find <dir> -exec rename 'y/a-z/A-Z/' {} \;
Warwick
C'est un peu plus compliqué que cela, car vous findrenommez des répertoires tout en y récursif.
Gilles 'SO- arrête d'être méchant'
@ Gilles - OK. Après avoir fait un peu de recherche, il semble que je doive ajouter l'option -depth pour trouver afin que les noms de répertoire soient gérés en dernier. Il find <dir> -depth -exec rename 'y/a-z/A-Z/' {} \;faut donc gérer le problème de renommage des répertoires. Correct?
Warwick
Non, cela ne fonctionne toujours pas, parce que les renamechangements , par exemple foo/barà FOO/BARet FOOn'existe pas à ce moment - là.
Gilles 'SO- arrête d'être méchant'
2

Je voudrais diriger toute personne qui est toujours liée à cette réponse à l'excellente réponse que Guiles Quernot a donnée à cette question qui ne nécessite pas find.

La commande résultante serait:

shopt -s globstar
rename -n 'y/a-z/A-Z/' **

Mais avant d'exécuter, veuillez lire la réponse liée pour les mises en garde concernant les anciennes versions de bash.

Enfin, au cas où quelqu'un se demanderait ce que fait la y///commande perl regex. Voici un lien vers la documentation pertinente .

Marcelo Lacerda
la source
1

find -execdir| Renommer

Ce serait le meilleur moyen de le faire sans la folie relative du chemin, car cela évite que Perl regex fu n'agisse que sur le nom de base:

PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
  find a -depth -execdir rename 's/(.*)/\U$1/' '{}' \;

-execdird'abord cddans le répertoire avant d'exécuter uniquement sur le nom de base.

Malheureusement, je ne peux pas me débarrasser de cette PATHpartie de piratage, find -execdirrefuse de faire quoi que ce soit si vous avez un chemin relatif dans PATH...: /ubuntu/621132/why-using-the-execdir-action- is-insecure-for-directory-which-is-in-the-path / 1109378 # 1109378

Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功
la source
0

Essayez ceci après avoir déplacé vers le répertoire où vous souhaitez renommer les fichiers:

for word in `ls -ltr |tail -n +2 |awk '{print $9}'`
do
  a=$(echo $word | tr '[a-z]' '[A-Z]')
  mv $word $a
  echo "Done Successfully"
done
Sorav
la source
N'analysez pas la sortie de ls (et pourquoi diable courriez-vous ls -luniquement pour couper les colonnes autres que le nom?), Et utilisez des guillemets doubles autour des substitutions de variables . Votre code est trop complexe et se casse sur les noms de fichiers contenant des espaces et d'autres caractères spéciaux. Utilisez findou **/pour rentrer dans des sous-répertoires, la sortie de lsest uniquement destinée à la consommation humaine.
Gilles 'SO- arrête d'être méchant'