Ho molti file con estensione .abc
e voglio cambiarli in .edefg
Come farlo dalla riga di comando?
Ho una cartella radice con molte sottocartelle, quindi la soluzione dovrebbe funzionare in modo ricorsivo.
Ho molti file con estensione .abc
e voglio cambiarli in .edefg
Come farlo dalla riga di comando?
Ho una cartella radice con molte sottocartelle, quindi la soluzione dovrebbe funzionare in modo ricorsivo.
Un modo portatile (che funzionerà su qualsiasi sistema conforme a POSIX):
find /the/path -depth -name "*.abc" -exec sh -c 'mv "" "${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 comando (perl) rename
in Ubuntu può rinominare i file usando la sintassi perl regular expression, 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 link
Questo 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, usa questo:
find /path/to/root/folder -type f -name '*.abc' -print0 | xargs -0 rename 's/.abc$/.edefg/'
Un problema con i nomi ricorsivi è che qualunque metodo tu usi per localizzare i file, passa l'intero percorso a rename
, non solo al nome del file. Ciò rende difficile la definizione di nomi complessi nelle cartelle nidificate.
Uso l'azione find
di -execdir
per risolvere questo problema. Se si utilizza -execdir
anziché -exec
, il comando specificato viene eseguito dalla sottodirectory contenente il file corrispondente. Quindi, anziché passare l'intero percorso a rename
, passa solo ./filename
. Ciò rende molto più facile scrivere la regex.
find /the/path -type f \
-name '*.abc' \
-execdir rename 's/\.\/(.+)\.abc$/version1_.abc/' '{}' \;
In dettaglio:
-type f
significa solo cercare file, non directory -name '*.abc'
significa significa solo nomi di corrispondenze che terminano in .abc -type
e -name
sono i caratteri di continuazione della riga bash. Li uso per rendere questo esempio più leggibile, ma in pratica non sono necessari. -execdir
. È lì per esacpe il punto e virgola, che termina il comando eseguito da -execdir
. Fun! Spiegazione della regex:
s/
inizio della regex \.\/
corrisponde al primo ./ che passa -execdir. Usa \ per sfuggire al. e / metacaratteri (.+)
corrisponde al nome file. Le parentesi catturano la corrispondenza per un uso successivo \.abc
sfugge al punto, corrisponde a abc $
ancora la corrispondenza alla fine della stringa
/
segna la fine della parte "match" della regex e l'inizio della parte "replace"
version1_
aggiungi questo testo a ogni nome di file
fa riferimento al nome file esistente, perché lo abbiamo catturato con parentesi. Se utilizzi più set di parentesi nella parte "match", puoi fare riferimento a loro qui usando $ 2, $ 3, ecc. .abc
il nuovo nome del file terminerà in .abc. Non è necessario sfuggire al punto metacarattere qui nella sezione "Sostituisci" /
alla fine della regex Prima
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: l'opzione -n di rename
è utile. Effettua un ciclo di prova e ti mostra quali nomi cambierà, ma non apporta alcuna modifica.
Un altro modo portatile:
find /the/path -depth -type f -name "*.abc" -exec sh -c 'mv -- "" "$(dirname "")/$(basename "" .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 basename, la tua sintassi sarebbe:
for f in *.txt; do
mv -- "$f" "$(basename "$f" .txt).text"
done
Questo è quello che ho fatto e ho funzionato bene proprio come volevo. Ho usato il comando mv
. Ho avuto più% file% di file e volevo rinominarli tutti in .3gp
Ecco un breve oneliner per questo:
for i in *.3gp; do mv -- "$i" "ren-$i.mp4"; done
Che scansiona semplicemente la directory corrente, raccoglie tutti i file .3gp, quindi rinomina (usando il mv) in .mp4
Ho trovato un modo semplice per raggiungere questo obiettivo. Per cambiare le estensioni di molti file da jpg a pdf, usa:
for file in /path/to; do mv $file $(basename -s jpg $file)pdf ; done
Vorrei utilizzare il comando mmv dal pacchetto con lo stesso nome :
mmv ';*.abc' '#1#2.edefg'
Il ;
corrisponde a zero o più */
e corrisponde a #1
nella sostituzione. Il *
corrisponde a #2
. La versione non ricorsiva sarebbe
mmv '*.abc' '#1.edefg'
Leggi altre domande sui tag command-line bash rename batch-rename