Risposte:
Un modo portatile (che funzionerà su qualsiasi sistema conforme a POSIX):
find /the/path -depth -name "*.abc" -exec sh -c 'mv "$1" "${1%.abc}.edefg"' _ {} \;
In bash4, puoi usare globstar per ottenere globi ricorsivi (**):
shopt -s globstar
for file in /the/path/**/*.abc; do
mv "$file" "${file%.abc}.edefg"
done
Il rename
comando (perl) in Ubuntu può rinominare i file usando la sintassi delle espressioni regolari perl, che puoi combinare con globstar o find
:
# Using globstar
shopt -s globstar
files=(/the/path/**/*.abc)
# Best to process the files in chunks to avoid exceeding the maximum argument
# length. 100 at a time is probably good enough.
# See http://mywiki.wooledge.org/BashFAQ/095
for ((i = 0; i < ${#files[@]}; i += 100)); do
rename 's/\.abc$/.edefg/' "${files[@]:i:100}"
done
# Using find:
find /the/path -depth -name "*.abc" -exec rename 's/\.abc$/.edefg/' {} +
Vedi anche http://mywiki.wooledge.org/BashFAQ/030
${1%.abc}...
sh -c
il primo argomento è assegnato a $ 0 e tutti gli argomenti rimanenti sono assegnati ai parametri posizionali . Quindi _
è un argomento fittizio e '{}' è il primo argomento posizionale a sh -c
.
Ciò eseguirà l'attività richiesta se tutti i file si trovano nella stessa cartella
rename 's/.abc$/.edefg/' *.abc
Per rinominare i file in modo ricorsivo, utilizzare questo:
find /path/to/root/folder -type f -name '*.abc' -print0 | xargs -0 rename 's/.abc$/.edefg/'
rename 's/.abc$/.edefg/' /path/to/root/folder/**/*.abc
in una versione moderna di Bash.
s
all'inizio e quali altre opzioni posso usare lì dentro. Grazie !
Un problema con le rinominazioni ricorsive è che qualunque metodo usi per localizzare i file, passa l'intero percorso rename
, non solo il nome del file. Ciò rende difficile eseguire rinominazioni complesse nelle cartelle nidificate.
Uso find
l’ -execdir
azione per risolvere questo problema. Se si utilizza -execdir
invece di -exec
, il comando specificato viene eseguito dalla sottodirectory contenente il file corrispondente. Quindi, invece di passare l'intero percorso rename
, passa solo ./filename
. Ciò rende molto più semplice scrivere la regex.
find /the/path -type f \
-name '*.abc' \
-execdir rename 's/\.\/(.+)\.abc$/version1_$1.abc/' '{}' \;
In dettaglio:
-type f
significa solo cercare file, non directory-name '*.abc'
indica solo i nomi dei file che terminano in .abc'{}'
è il segnaposto che contrassegna il punto in cui -execdir
verrà inserito il percorso trovato. Le virgolette singole sono necessarie per consentire la gestione dei nomi dei file con spazi e caratteri shell.-type
e -name
sono il carattere di continuazione della riga bash. Li uso per rendere questo esempio più leggibile, ma non sono necessari se si inserisce il comando su una riga.-execdir
riga. È lì per sfuggire al punto e virgola, che termina il comando eseguito da -execdir
. Divertimento!Spiegazione della regex:
s/
inizio della regex\.\/
corrisponde al comando ./ che passa -execdir. Usa \ per sfuggire a. e / metacaratteri (nota: questa parte varia in base alla versione di find
. Vedi commento dell'utente @apollo)(.+)
corrisponde al nome del file. Le parentesi catturano la corrispondenza per un uso successivo\.abc
sfuggire al punto, abbinare l'abc$
ancorare la corrispondenza alla fine della stringa
/
segna la fine della parte "match" del regex e l'inizio della parte "sostituisci"
version1_
aggiungi questo testo ad ogni nome di file
$1
fa riferimento al nome file esistente, perché l'abbiamo catturato tra parentesi. Se usi più set di parentesi nella parte "match", puoi fare riferimento a questi qui usando $ 2, $ 3, ecc..abc
il nuovo nome del file terminerà con .abc. Non è necessario sfuggire al punto metacarattere nella sezione "Sostituisci"/
fine della regexPrima
tree --charset=ascii
|-- a_file.abc
|-- Another.abc
|-- Not_this.def
`-- dir1
`-- nested_file.abc
Dopo
tree --charset=ascii
|-- version1_a_file.abc
|-- version1_Another.abc
|-- Not_this.def
`-- dir1
`-- version1_nested_file.abc
Suggerimento: rename
l'opzione 's -n è utile. Fa una corsa a secco e ti mostra quali nomi cambierà, ma non apporta alcuna modifica.
--execdir
non è passato in testa ./
quindi la \.\/
parte nella regex può essere omessa. Che sia perché sono su OSX non su Ubuntu
Un altro modo portatile:
find /the/path -depth -type f -name "*.abc" -exec sh -c 'mv -- "$1" "$(dirname "$1")/$(basename "$1" .abc).edefg"' _ '{}' \;
# Rename all *.txt to *.text
for f in *.txt; do
mv -- "$f" "${f%.txt}.text"
done
Vedi anche la voce sul perché non dovresti analizzare ls
.
Modifica: se devi usare il nome di base la tua sintassi sarebbe:
for f in *.txt; do
mv -- "$f" "$(basename "$f" .txt).text"
done
https://unix.stackexchange.com/questions/19654/changing-extension-to-multiple-files
Questo è quello che ho fatto e lavorato abbastanza come volevo. Ho usato il mv
comando. Avevo più .3gp
file e volevo rinominarli tutti.mp4
Ecco un breve suggerimento per questo:
for i in *.3gp; do mv -- "$i" "ren-$i.mp4"; done
Che semplicemente scansiona la directory corrente, raccoglie tutti i file .3gp, quindi rinomina (usando mv) in ren-name_of_file.mp4
file.3gp
in file.3gp.mp4
, che potrebbe non essere quello che la maggior parte delle persone desidera.
.3gp
o .mp4
qui erano solo a scopo illustrativo.
basename "$i" .mp4
rimuovere l'estensione precedente invece di "ren- $ i.mp4".
Ho trovato un modo semplice per raggiungere questo obiettivo. Per modificare le estensioni di molti file da jpg a pdf, utilizzare:
for file in /path/to; do mv $file $(basename -s jpg $file)pdf ; done
Userei il comando di MMV dal pacchetto con lo stesso nome :
mmv ';*.abc' '#1#2.edefg'
Le ;
partite corrispondono a zero o più */
e corrispondono a #1
nella sostituzione. Il *
corrisponde a #2
. La versione non ricorsiva sarebbe
mmv '*.abc' '#1.edefg'
Rinominare file e directory con find -execdir | rename
Se hai intenzione di rinominare sia i file che le directory non semplicemente con un suffisso, allora questo è un buon modello:
PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
find . -depth -execdir rename 's/findme/replaceme/' '{}' \;
La fantastica -execdir
opzione fa un cd
nella directory prima di eseguire il rename
comando, a differenza -exec
.
-depth
assicurarsi che la ridenominazione avvenga prima sui figli, e poi sui genitori, per prevenire potenziali problemi con le directory dei genitori mancanti.
-execdir
è necessario perché la ridenominazione non viene riprodotta correttamente con percorsi di input senza nome di base, ad esempio i seguenti errori:
rename 's/findme/replaceme/g' acc/acc
L' PATH
hacking è necessario perché -execdir
ha uno svantaggio molto fastidioso: find
è estremamente supponente e si rifiuta di fare qualsiasi cosa -execdir
se ci sono percorsi relativi nella PATH
variabile di ambiente, ad esempio ./node_modules/.bin
, non riuscendo con:
find: il percorso relativo './node_modules/.bin' è incluso nella variabile d'ambiente PATH, che non è sicura in combinazione con l'azione -execdir di find. Rimuovi quella voce da $ PATH
Vedi anche: Perché l'uso dell'azione '-execdir' non è sicuro per la directory che si trova nel PERCORSO?
-execdir
è un'estensione di ricerca GNU a POSIX . rename
è basato su Perl e proviene dal rename
pacchetto. Testato su Ubuntu 18.10.
Rinomina soluzione alternativa lookahead
Se i tuoi percorsi di input non provengono find
o se hai abbastanza del fastidio relativo del percorso, possiamo usare alcuni lookahead Perl per rinominare in modo sicuro le directory come in:
git ls-files | sort -r | xargs rename 's/findme(?!.*\/)\/?$/replaceme/g' '{}'
Non ho trovato un analogo conveniente per -execdir
con xargs
: https://superuser.com/questions/893890/xargs-change-working-directory-to-file-path-before-executing/915686
Il sort -r
è tenuto a garantire che i file vengono dopo rispettive directory, dal momento che i percorsi più lunghi vengono dopo quelle più corte con lo stesso prefisso.