Je veux mettre en minuscule le nom de chaque répertoire sous un répertoire. Avec quelles commandes puis-je faire cela?
la source
Je veux mettre en minuscule le nom de chaque répertoire sous un répertoire. Avec quelles commandes puis-je faire cela?
Tous les répertoires à un niveau, ou récursivement?
À un niveau:
autoload zmv
zmv -o-i -Q 'root/(*)(/)' 'root/${1:l}'
Récursivement:
zmv -o-i -Q 'root/(**/)(*)(/)' 'root/$1${2:l}'
Explications: zmv
renomme les fichiers correspondant à un modèle en fonction du texte de remplacement donné. -o-i
passe l' -i
option à chaque mv
commande sous le capot (voir ci-dessous). Dans le texte de remplacement, $1
, $2
, etc, sont les groupes successifs dans le parenthésées modèle. **
signifie tous les répertoires (sous) *, récursivement. La finale (/)
n'est pas un groupe entre parenthèses mais un qualificatif glob qui signifie ne correspondre qu'aux répertoires. ${2:l}
convertit $2
en minuscules.
À un niveau:
for x in root/*/; do mv -i "$x" "$(printf %s "$x" | tr '[:upper:]' '[:lower:]')"; done
La finale /
limite la correspondance aux répertoires et lui mv -i
fait demander une confirmation en cas de collision. Retirez le -i
pour écraser en cas de collision et utilisez yes n | for …
. pour ne pas être invité et ne pas effectuer de changement de nom qui entrerait en collision.
Récursivement:
find root/* -depth -type d -exec sh -c '
t=${0%/*}/$(printf %s "${0##*/}" | tr "[:upper:]" "[:lower:]");
[ "$t" = "$0" ] || mv -i "$0" "$t"
' {} \;
L'utilisation de -depth
assure que les répertoires profondément imbriqués sont traités avant leurs ancêtres. Le traitement du nom repose sur l'existence d'un /
; si vous voulez appeler operer dans le répertoire courant, utilisez ./*
(l'adaptation du script shell pour faire face .
ou *
est laissé comme exercice pour le lecteur).
Ici, j'utilise le script de changement de nom Perl /usr/bin/prename
fourni par Debian et Ubuntu (généralement également disponible rename
). À un niveau:
rename 's!/([^/]*/?)$!\L/$1!' root/*/
Récursivement, avec bash ≥4 ou zsh:
shopt -s globstar # only in bash
rename 's!/([^/]*/?)$!\L/$1!' root/**/*/
De manière récursive, portable:
find root -depth -type d -exec rename -n 's!/([^/]*/?)$!\L/$1!' {} +
mv -i a a
donnez "mv: rename a à a / a: Argument invalide".-execdir
ce qui est génial: unix.stackexchange.com/questions/5412/… J'ai ensuite trouvé qu'il y avait de laPATH
folie et était triste :-(Il n'y a pas une seule commande qui fera cela, mais vous pouvez faire quelque chose comme ceci:
Si vous en avez besoin pour être robuste, vous devez tenir compte du fait qu'il existe déjà deux répertoires qui ne diffèrent qu'en cas.
En une ligne:
la source
for file in * ; do if [ -d "$file" ] ; then dest="$(echo $file | sed y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/)" ; [ "$dest" != "$file" ] && mv "$file" "$dest" ; fi ; done
find -type d
, mais je n'arrivais pas à comprendrefor fd in */;
, évitant ainsi la nécessité de vérifier s'il s'agissait d'un répertoire, mais je n'ai aucune idée si cet instinct était bon.tr
attend déjà une gamme, donctr '[A-Z]' '[a-z]'
traduit[
à[
et]
à]
en passant. C'est inutile mais inoffensif; cependant, sans les guillemets, le shell étendrait les crochets s'il y avait un fichier avec un nom à une lettre majuscule dans le répertoire courant.J'ai pris cela comme un défi à une ligne :) Commencez par établir un scénario de test:
J'utilise
find
pour repérer les répertoires avec des lettres majuscules, puis les télécharger via . Je suppose que l'utilisation est un peu hack-ish, mais ma tête explose toujours lorsque j'essaie d'échapper aux choses directement.sh -c 'mv {}
echo {} | tr [:upper:] [:lower:]
'sh -c
find
Attention: cette solution ne vérifie pas si la rétrogradation entraîne des collisions!
la source
mv -i
. Un problème plus important est que vous n'avez pas utilisé de guillemets appropriés, donc votre commande échouera s'il y a des caractères spéciaux (espaces ou\[*?
) n'importe où dans le nom. Il n'y a aucun intérêt à l'utiliser àfind
moins que ce ne soit récursif, et alors vous en avez besoinfind -depth
et-path
devez l'être-name
. Voir ma réponse pour des exemples de travail.mv -i
après avoir écrit ceci. Bon point avec la citation ...find -execdir
| RenommerCe serait la meilleure façon de le faire sans la folie relative du chemin, car cela évite que Perl regex fu n'agisse que sur le nom de base:
-execdir
d'abordcd
dans le répertoire avant d'exécuter uniquement sur le nom de base.Malheureusement, je ne peux pas me débarrasser de cette
PATH
partie de piratage,find -execdir
refuse de faire quoi que ce soit si vous avez un chemin relatif dansPATH
: /ubuntu/621132/why-using-the-execdir-action- is-insecure-for-directory-which-is-in-the-path / 1109378 # 1109378la source