Anche la domanda in sé non è esatta, perché l'OP parla di:
- nomi di file come
ABC 123456
(senza estensione), ma nel codice di esempio usando *.txt
estensione
- aggiungi un trattino tra due blocchi (ad esempio dov'è lo spazio)
ABC - 123456
, ma nel prossimo prendere circa counting to 4
e count 3
, per esempio. non esattamente chiaro cosa dovrebbe fare lo script, ad esempio se trova ABCD 12
o AB 345
- inoltre, vuoi mantenere lo spazio finale, ciò che è strano - ma OK;)
Il problema è divisibile in 3 parti separate:
- selezionando i file giusti per la rinomina
- preparare il nuovo nome file, sostituendo / aggiungendo caratteri al vecchio
- il nome "fisico"
Annuncio "selezione dei file giusti". La selezione dei file può essere eseguita da alcune utilità esterne, ad esempio da find
comando.
I principali vantaggi del find
siamo:
- può cercare i file in modo ricorsivo anche nelle sottodirectory
- è possibile selezionare con maggiore precisione i file giusti, ad es. escludere le directory, selezionare i file in base al tempo o alle dimensioni e così via. (controllare dal terminale
man find
.)
Annuncio "prepara il nuovo nome". Questo può essere fatto da programmi esterni,
piace sed
o awk
o qualsiasi programma cosa può manipolare il testo nella shell
script, o può essere fatto (in alcuni casi semplici come questo) all'interno
il bash
stesso - ed è possibile salvare una costosa esecuzione di comandi.
(per hundert di migliaia di file fa la differenza).
Il seguente:
${file/ /-}
sostituisce (sostituisce) uno spazio (il / /
parte) con il trattino ( /-
). Quindi è possibile scrivere
mv "$file" "${file/ /-}"
e salvare il sed
esecuzione.
Quindi una delle soluzioni alternative potrebbe essere , ad esempio il seguente:
#!/bin/bash
while IFS= read -r -d $'\0' filename
do
newfilename="${filename/ /-}"
[[ "$filename" != "$newfilename" ]] && echo mv -i "$filename" "$newfilename"
done < <(find . -maxdepth 1 -type f -iname "* *.jpg" -print0)
Quanto sopra è per il FUNZIONAMENTO A SECCO - mostrerà solo, cosa verrà fatto, per la vera esecuzione rimuovere il echo
.
Decomposizione:
selezionando i file giusti per la rinomina: il find . -maxdepth 1 -type f -iname "* *.jpg" -print0
troverà tutto
- cosa sono solo nella directory corrente (
-maxdepth 1
)
- e loro sono file semplici (
-type f
)
- e il loro nome corrisponde (Nulla) (spazio) (nulla) .jpg caso insensibile - ad es. il nome deve contenere uno spazio
- fornire i nomi dei file come null terminato , quindi il loro nome può tranquillamente contenere anche il carattere di nuova riga. (
-print0
)
il ciclo while IFS= read -r -d $'\0' filename; do ... done < <( )
- legge l'output da quanto sopra
find
comando
- dove sono i nomi dei file null terminato (
-d $'\0'
)
- ignora tutti i personaggi in fuga (
-r
) / argomento avanzato - non necessario per spiegare qui /
- il
IFS=
impedisce il taglio degli spazi bianchi iniziali e finali dal nome del file (anche un argomento un po 'avanzato)
preparare il nuovo nome file newfilename="${filename/ /-}"
- è fatto da
bash
internamente (senza eseguire un comando esterno).
- se vuoi preservare lo spazio finale dopo l'uso del trattino
${filename/ /- }
l'attuale ridenominazione viene eseguita da mv
comando (vedi man mv
dal terminale), dove
- il
-i
cosa chiederà all'utente se qui è già un file con il nuovo nome file (non sovrascriverlo)
e il mv
viene eseguito solo quando il newfilename
è diverso dal filename
[[ "$filename" != "$newfilename" ]]
La soluzione di cui sopra è per lo più soggetta a errori, ma non è ancora molto efficace,
perché per centinaia di migliaia di file verranno eseguite centinaia di
mille volte il mv
comando.
La soluzione può essere: usando alcuni
utilità, che cosa può leggere i nomi dei file e fare la ridenominazione senza
eseguendo il mv
comando N-volte.
Ad esempio, la "grande pistola" del sistema ammette il "perl", come:
find . -maxdepth 1 -type f -iname "*.jpg" -print0 |\
perl -0nle '$n=$_; $n=~s/ /-/; rename $_,$n unless($_ eq $n || -e $n)'
ciò che rinominerà tutti i file ciò che produce il find
in una esecuzione - ad es. molto più veloce di migliaia di mv
esecuzioni.
Tor testing (DRY RUN) usa il seguente:
find . -maxdepth 1 -type f -iname "*.jpg" -print0 |\
perl -0nle '$n=$_; $n=~s/ /-/; print qq{old:$_ new:$n\n} unless($_ eq $n || -e $n)' #print instead of the rename
Ps: il perl è abbastanza potente da gestire tutto da solo, ad es. anche il comando find, ma è un argomento più avanzato ...
Ps2: il mio inglese è molto peggio del mio bash
, quindi qualcuno potrebbe gentilmente modificare questo post per aggiungere / correggere le cose ..;)