Rende minuscole tutte le directory in una directory


Risposte:


10

Tutte le directory a un livello o ricorsivamente?

zsh

A un livello:

autoload zmv
zmv -o-i -Q 'root/(*)(/)' 'root/${1:l}'

ricorsivamente:

zmv -o-i -Q 'root/(**/)(*)(/)' 'root/$1${2:l}'

Spiegazioni: zmvrinomina i file corrispondenti a un modello in base al testo di sostituzione fornito. -o-ipassa l' -iopzione a ciascun mvcomando sotto il cofano (vedi sotto). Nel testo di sostituzione, $1, $2, ecc, sono i successivi gruppi tra parentesi nel modello. **indica tutte le (sotto) * directory, ricorsivamente. Il finale (/)non è un gruppo tra parentesi ma un qualificatore glob che intende abbinare solo le directory. ${2:l}converte $2in minuscolo.

Portatile

A un livello:

for x in root/*/; do mv -i "$x" "$(printf %s "$x" | tr '[:upper:]' '[:lower:]')"; done

Il finale /limita la corrispondenza con le directory e lo mv -ifa chiedere conferma in caso di collisione. Rimuovere -iper sovrascrivere in caso di collisione e utilizzare yes n | for …. non essere richiesto e non eseguire alcuna ridenominazione che potrebbe scontrarsi.

ricorsivamente:

find root/* -depth -type d -exec sh -c '
    t=${0%/*}/$(printf %s "${0##*/}" | tr "[:upper:]" "[:lower:]");
    [ "$t" = "$0" ] || mv -i "$0" "$t"
' {} \;

L'uso di -depthassicura che le directory profondamente annidate vengano elaborate prima dei loro antenati. L'elaborazione del nome si basa sull'esistenza di un /; se vuoi chiamare operi nella directory corrente, usa ./*(adattando lo script della shell per far fronte .o *viene lasciato come esercizio per il lettore).

Rinominare il Perl

Qui uso lo script di rinomina Perl /usr/bin/prenamefornito da Debian e Ubuntu (normalmente disponibile renameanche). A un livello:

rename 's!/([^/]*/?)$!\L/$1!' root/*/

Ricorsivamente, con bash ≥4 o zsh:

shopt -s globstar  # only in bash
rename 's!/([^/]*/?)$!\L/$1!' root/**/*/

Ricorsivamente, portabilmente:

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

Almeno su OS X questo fallirà se qualche directory è già in minuscolo: mv -i a adare "mv: rinomina a a / a: argomento non valido".
Janus,

@Janus: Giusto, ricevi un messaggio di errore, che è brutto (anche se innocuo nella riga di comando). Ma comunque avrei dovuto usare zmv, che si occupa di questo caso.
Gilles 'SO- smetti di essere cattivo' il

Poi ho scoperto -execdirche è fantastico: unix.stackexchange.com/questions/5412/… Ho poi scoperto che ha un po 'di PATHfollia ed è stato triste :-(
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

4

Non esiste un singolo comando che lo farà, ma puoi fare qualcosa del genere:

for fd in */; do
  #get lower case version
  fd_lower=$(printf %s "$fd" | tr A-Z a-z)
  #if it wasn't already lowercase, move it.
  [ "$fd" != "$fd_lower" ] && mv "$fd" "$fd_lower"
done

Se è necessario che sia robusto, è necessario tenere conto di quando esistono già due directory che differiscono solo nel caso.

Come una linea:

for fd in */; do fd_lower=$(printf %s "$fd" | tr A-Z a-z) && [ "$fd" != "$fd_lower" ] && mv "$fd" "$fd_lower"; done

Questo è emerso a metà strada attraverso la mia scrittura del suggerimento (sostanzialmente lo stesso):for file in * ; do if [ -d "$file" ] ; then dest="$(echo $file | sed y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/)" ; [ "$dest" != "$file" ] && mv "$file" "$dest" ; fi ; done
frabjous

Stavo cercando di risolverlo find -type d, ma non ci sono riuscito
Michael Mrozek

1
Il mio istinto sarebbe stato quello di fare for fd in */;, evitando così la necessità di verificare se fosse una directory, ma non ho idea se questo istinto fosse buono.
Steven D,

Sì, per ... * / sarebbe meglio.
Shawn J. Goff,

1
@Shawn: si traspetta già un intervallo, quindi si tr '[A-Z]' '[a-z]'traduce [da [e ]verso ]di passaggio. Questo è inutile ma innocuo; tuttavia senza le virgolette la shell espanderebbe le parentesi se ci fosse un file con un nome di una lettera maiuscola nella directory corrente.
Gilles 'SO- smetti di essere malvagio' il

0

Ho preso questo come una sfida di un liner :) In primo luogo, stabilire un caso di prova:

$ for d in foo Bar eVe; do mkdir -p dcthis/$d; touch dcthis/a${d}.txt; done
$ ls dcthis/
Bar     aBar.txt    aeVe.txt    afoo.txt    eVe     foo

Uso findper individuare le directory con le lettere maiuscole e poi le ho minuscole . Immagino che usare sia un po 'hack-ish, ma la mia testa esplode sempre quando provo a sfuggire alle cose per direttamente.sh -c 'mv {} echo {} | tr [:upper:] [:lower:]'sh -cfind

$ (cd dcthis && find . -maxdepth 1 -type d -path '*[A-Z]*' -exec sh -c 'mv {} `echo {} | tr [:upper:] [:lower:]`' \;)
$ ls dcthis/
aBar.txt    aeVe.txt    afoo.txt    bar     eve     foo

Attenzione: questa soluzione non controlla se il downcasing porta a collisioni!


il controllo di collisioni è facile: mv -i. Un problema più grande è che non hai usato la quotazione corretta, quindi il tuo comando fallirà se ci sono caratteri speciali (spazi bianchi o \[*?) in qualsiasi parte del nome. Non ha senso utilizzare a findmeno che non si ripeta, quindi è necessario find -depthe -pathdeve esserlo -name. Vedi la mia risposta per esempi funzionanti.
Gilles 'SO- smetti di essere malvagio' il

@Giles. Grazie! Ti ho visto mv -idopo aver scritto questo. Buon punto con la citazione ...
Janus

0

find -execdir| rinominare

Questo sarebbe il modo migliore per farlo se non fosse per la follia del percorso relativo, poiché evita che Perl regex fu agisca solo sul nome di base:

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

-execdirprima cds nella directory prima di eseguire solo sul basename.

Sfortunatamente, non riesco a liberarmi di quella PATHparte di hacking, mi find -execdirrifiuto di fare qualsiasi cosa se hai un percorso relativo in PATH...: /ubuntu/621132/why-using-the-execdir-action- è-insicuro-per-directory-che-è-in-the-path / 1.109.378 1.109.378 #

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.