Wie ersetze ich Leerzeichen in allen Dateinamen mit einem Unterstrich in Linux mithilfe eines Shell-Skripts?

16

Ich habe versucht, folgende Shell-Skript, die Leerzeichen aus allen XML-Dateinamen ersetzen sollte

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

Angenommen, ich habe eine XML-Datei mit dem Namen xy z.xml, dann gibt es:

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
krishna
quelle

Antworten:

26

Verwenden Sie dies mit bash:

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

findsucht nach Dateien mit einem Leerzeichen im Namen. Die Dateinamen werden mit einem Nullbyte ( -print0) als Trennzeichen gedruckt , um auch mit speziellen Dateinamen fertig zu werden. Dann readliest das Builtin die durch das Nullbyte begrenzten Dateinamen und mversetzt schließlich die Leerzeichen durch einen Unterstrich.

BEARBEITEN: Wenn Sie die Leerzeichen in den Verzeichnissen auch entfernen möchten, ist es ein bisschen komplizierter. Die Verzeichnisse werden umbenannt und sind dann nicht mehr über den Namen find erreichbar find. Versuche dies:

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

Das sort -rzkehrt die Datei um, so dass die tiefsten Dateien in einem Ordner sind die ersten , sich zu bewegen und die Ordner selbst wird die letzte sein. Es werden also niemals Ordner umbenannt, bevor nicht alle Dateien und Ordner darin umbenannt wurden. Der mvBefehl in der Schleife wurde ebenfalls etwas geändert. Im Zielnamen entfernen wir nur die Leerzeichen im Basisnamen der Datei, da sonst kein Zugriff möglich ist.

Chaos
quelle
Ich versuche, Leerzeichen in allen Verzeichnissen durch Unterstriche zu ersetzen, aber es wird ein Fehler ausgegeben, da nach dem Ändern des Namens auf dieses Verzeichnis nicht zugegriffen werden kann.
Krishna
@krishna Ich habe meiner Antwort eine Änderung hinzugefügt.
Chaos
1
@chaos wow, habe gerade diese beiden auf zwei Systemen ausgeführt und es hat wie ein Zauber funktioniert, ein paar Dateien und Verzeichnisse werden nicht durchlaufen, aber es sind nur ein paar
irgendwas
Unter macOS müssen wir das Verzeichnis im Befehl find vor der Option -name angebenfind . -name "* *" -print0 | sort -rz | \ while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done
Laszlo Pinter,
16
  1. Verwenden rename

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

    oder mit $1

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

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

    oder mit $1

    find "$1" -type f -name "* *.xml" -exec bash -c 'mv "$0" "${0// /_}"' {} \;
AB
quelle
Ich weiß nicht warum, aber Ihr Befehl funktioniert bei mir nicht. Es wird kein Fehler und keine Ausgabe angezeigt.
Krishna
@ krishna korrigiert, sorry
AB
1
Rename hat für mich gearbeitet. Fauststoß!
Brian Piercy
1

Dies ist eine Methode, die ich vor dem gleichen Problem gefunden habe:

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

Ich habe eine Bash-Skriptdatei geschrieben, um meine SSL-Zertifikate automatisch zu aktualisieren.

NekoMisaki
quelle
1

Verwendung rename:

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

Keine Notwendigkeit für find:)

Jan Werkhoven
quelle
1
füge das nachstehende g zum regulären Ausdruck hinzu und es funktioniert einwandfrei. 's / \ s / _ / g'
jbrahy
Guter Tipp, danke :)
Jan Werkhoven