2010-12-22 11 views

risposta

59

rename è pericolosa, poiché secondo la sua pagina di manuale:

rinomina rinominerà i file specificati sostituendo il primo occorrenza di ...

Sarà felicemente fare la cosa sbagliata con nomi file come c.txt.parser.y.

Ecco una soluzione che utilizza find e bash:

find -type f -name '*.txt' | while read f; do mv "$f" "${f%.txt}"; done 

Tenete a mente che questo si romperà se il nome del file contiene un ritorno a capo (raro, ma non impossibile).

Se avete GNU trovare, questa è una soluzione più solida:

find -type f -name '*.txt' -print0 | while read -d $'\0' f; do mv "$f" "${f%.txt}"; done 
+1

È vero per quanto riguarda la versione 'util-linux-ng' di' rename', ma la versione dello script Perl può 'rinominare'/.txt $ // '* .txt' –

+0

per me rinominare' s/.txt $ // '* .txt non ha funzionato – rp101

+1

se ti manca la corrente "." per quanto riguarda la posizione in cui si desidera eseguire. Forse questa è la mia variante osx di find, o il mio percorso non è impostato correttamente – bgs

10

È possibile passare esplicitamente una stringa vuota come argomento.

rename .old '' *.old

E con sottocartelle, find . -type d -exec rename .old '' {}/*.old \;. {} è il sostituto per la voce trovata con find e \; termina l'arglist per il comando dato dopo -exec.

1

Per sottocartelle:

for i in `find myfolder -type d`; do 
    rename .old .new $i/*.old 
done 
+2

Questo può causare problemi se c'è un nome di cartella con uno spazio in esso. – robert

15

Io uso questo:

find ./ -name "*.old" -exec sh -c 'mv $0 `basename "$0" .old`.new' '{}' \; 
+0

grazie, non conoscevo questa sintassi, e funziona anche su MacOSX (che manca nativo 'rename'). – Utopik

+0

funziona perfettamente con Windows Git Bash, grazie! – RaptoX

+0

Dovresti aver aggiunto la dirname nel caso in cui il target si trovi in ​​una sottocartella: find ./ -name "* .old" -exec sh -c 'mv $ 0 'dirname" $ ​​0 "'/'basename" $ ​​0 ".old' .new '' {} '\; –

13

La versione di Perl di rename può rimuovere un'estensione come segue:

rename 's/\.txt$//' *.txt 

Questo potrebbe essere combinato con trovare per fare anche sottocartelle.

1

In Fish, si può fare

for file in *.old 
     touch (basename "$file" .old).new 
end 
3

In caso aiuta, ecco come lo faccio con zsh:

for f in ./**/*.old; do 
    mv "${f}" "${f%.old}" 
done 

Il ${x%pattern} costrutto nella zsh rimuove più breve verificarsi di pattern al fine di $x.Qui si astrae in funzione:

function chgext() { 
    local srcext=".old" 
    local dstext="" 
    local dir="." 

    [[ "$#" -ge 1 ]] && srcext="$1" 
    [[ "$#" -gt 2 ]] && dstext="$2" dir="$3" || dir="${2:-.}" 

    local bname='' 
    for f in "${dir}"/**/*"${srcext}"; do 
     bname="${f%${srcext}}" 
     echo "${bname}{${srcext} → ${dstext}}" 
     mv "${f}" "${bname}${dstext}" 
    done 
} 

Usage:

chgext 
chgext src 
chgext src dir 
chgext src dst dir 

Where `src` is the extension to find (default: ".old") 
     `dst` is the extension to replace with (default: "") 
     `dir` is the directory to act on (default: ".") 
Problemi correlati