Come sostituire gli spazi in tutti i nomi di file con il trattino basso in Linux usando lo script della shell?


17

Ho provato a seguire lo script della shell che dovrebbe sostituire gli spazi di tutti i nomi di file XML

for xml_file in $(find $1 -name "* .xml" -type f);
do
 echo "removing spaces from XML file:" $xml_file
 mv "$xml_file" "${xml_file// /_}";
done

Supponiamo che io abbia un file XML con il nome xy z.xml, quindi dà:

removing spaces from XML file: /home/krishna/test/xy
mv: cannot stat `/home/krishna/test/xy': No such file or directory
removing spaces from XML file: .xml
mv: cannot stat `z.xml': No such file or directory

Risposte:


28

Usa questo con bash:

find $1 -name "* *.xml" -type f -print0 | \
  while read -d $'\0' f; do mv -v "$f" "${f// /_}"; done

findcercherà i file con uno spazio nel nome. I nomi dei file verranno stampati con un nullbyte ( -print0) come delimitatore per far fronte anche a nomi di file speciali. Quindi il readbuiltin legge i nomi dei file delimitati da nullbyte e infine mvsostituisce gli spazi con un carattere di sottolineatura.

EDIT: Se vuoi rimuovere anche gli spazi nelle directory, è un po 'più complicato. Le directory vengono rinominate e quindi non sono più accessibili con il nome findtrovato. Prova questo:

find -name "* *" -print0 | sort -rz | \
  while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done

Il sort -rzinverte l'ordine dei file, in modo che i file più profonde in una cartella sono i primi a muoversi e la cartella stessa sarà l'ultimo. Quindi, non ci sono mai cartelle rinominate prima che tutti i file e le cartelle vengano rinominati al suo interno. Anche il mvcomando nel loop è leggermente cambiato. Nel nome di destinazione, rimuoviamo solo gli spazi nel nome di base del file, altrimenti non sarebbe accessibile.


Sto cercando di sostituire gli spazi con la sottolineatura in tutte le directory ma sta dando errore perché dopo aver cambiato nome quella directory non è accessibile.
Krishna,

@krishna Ho aggiunto una modifica alla mia risposta.
caos

1
@chaos wow, ho appena eseguito questi due su due sistemi e ha funzionato come un incantesimo, pochi file e dir non passano ma sono solo alcuni
qualcosa di qualcosa di

Su macOS dobbiamo specificare la directory nel comando find prima dell'opzione -name find . -name "* *" -print0 | sort -rz | \ while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done
Laszlo Pinter

17
  1. utilizzando rename

    find . -type f -name "* *.xml" -exec rename "s/\s/_/g" {} \;

    o con $1

    find "$1" -type f -name "* *.xml" -exec rename "s/\s/_/g" {} \;
  2. utilizzando mv

    find . -type f -name "* *.xml" -exec bash -c 'mv "$0" "${0// /_}"' {} \;

    o con $1

    find "$1" -type f -name "* *.xml" -exec bash -c 'mv "$0" "${0// /_}"' {} \;

Non so perché ma il tuo dato comando non funziona per me. Non mostra alcun errore e output.
Krishna,

@krishna corretta, scusa
AB

1
Rinomina ha funzionato per me. Fistbump!
Brian Piercy,

1

Questo è un metodo che ho riscontrato affrontando lo stesso problema:

for f in *; do mv "$f" `echo $f | tr ' ' '_'`; done

Stavo scrivendo un file di script bash per aggiornare automaticamente i miei certificati ssl.


1

Utilizzare rename:

rename 's/\s/_/g' ./*.xml

Non c'è bisogno di find:)


1
aggiungi il g finale al regex e funziona perfettamente. 's / \ s / _ / g'
jbrahy

Un buon consiglio, grazie :)
Jan Werkhoven,
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.