Shell-Skript zum Korrigieren fehlerhafter Dateinamen?

Shell-Skript zum Korrigieren fehlerhafter Dateinamen?

Ich bin für die IT in meiner kleinen Firma zuständig, und trotz meiner eindringlichen Warnungen legt jeder Dateien mit furchtbaren Namen auf dem Server ab, einschließlich Leerzeichen am Anfang und Ende, ungültigen Zeichen (einschließlich \ ; / + . < > -usw.!).

Dies geschieht, indem auf Macs der Zugriff auf den (FreeBSD/FreeNAS-)Server über AFP erfolgt, sodass kein Teil des Systems Probleme verursacht.

Gibt es ein Skript, mit dem ich einen gesamten Verzeichnisbaum durchgehen und fehlerhafte Dateinamen korrigieren kann?

Ersetzen Sie grundsätzlich alle Leerzeichen und fehlerhaften ASCII-Zeichen durch _..., und wenn eine Datei bereits vorhanden ist, fügen Sie einfach ein _2oder etwas Ähnliches ans Ende.

Ich glaube nicht, dass es eine Möglichkeit gibt, das System dazu zu bringen,erzwingengute Konventionen für die Benennung von Dateien, oder?

Danke!

Antwort1

Ich würde Bash und Find verwenden. Ich bin sicher, dass es eine einfachere Option gibt, aber hier ist, was mir eingefallen ist:

  1. Dies kann mit Dateinamen umgehen, die "/" enthalten (find gibt eine Warnung aus, ignorieren Sie diese), aberEs funktioniert nur mit Dateien im aktuellen Verzeichnis(keine Unterverzeichnisse). Ich konnte nicht herausfinden, wie ich Bash oder Find dazu bringen kann, zwischen einem „/“ in einem Dateinamen und einem „/“ als Teil des Pfads zu unterscheiden.

    for i in $(find . -maxdepth 1 -type f  -name "*[\:\;><\@\$\#\&\(\)\?\\\/\%]*" | sed 's/\.\///'); do mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\\/\%]/_}; done
    
  2. Dieses hierkann nichtmit Dateinamen umgehen, die "/" enthalten, aber es funktioniert mit allen Dateien im aktuellen Verzeichnisund seine Unterverzeichnisse:

    for i in $(find . -type f  -name "*[\:\;\>\<\@\$\#\&\(\)\?\\\%]*"); do mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\\%]/_}; done
    

Stellen Sie sicher, dasstesten Sie diese vor dem Ausführen. Sie funktionierten in den wenigen Tests, die ich durchführte, einwandfrei, aber ich war nicht erschöpfend. Bedenken Sie auch, dass ich ein Linux-System verwende. Die konkrete Implementierung von find und vielleicht auch bash kann bei Ihnen anders sein.


BEARBEITEN: Wenn Sie den mv $iBefehl in „mv -i $i“ ändern, werden Sie von mv vor dem Überschreiben einer vorhandenen Datei nachgefragt.

EDIT2: Um mit Dateinamen mit Leerzeichen umzugehen, können Sie die Bash-IFS-Variable (Input Field Separator) wie folgt ändern (angepasst vonHier):

SAVEIFS=$IFS; IFS=$(echo -en "\n\b"); for i in $(find . -type f  -name "*[\:\;\>\<\@\$\#\&\(\)\?\\\%\ ]*"); do mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\\%\ ]/_}; done; IFS=$SAVEIFS

Ich habe auch den regulären Ausdruck geändert, um Leerzeichen durch Unterstriche zu ersetzen. Das SAVEIFS-Bit setzt die IFS-Variable einfach auf ihre ursprüngliche Konfiguration zurück.


ERLÄUTERUNG:

for i in $(command); do something $i; done

Dies ist eine generische Bash-Schleife. Sie durchläuft die Ausgabe eines Befehls, setzt die Variable $i nacheinander auf jeden vom Befehl zurückgegebenen Wert und führt eine Aktion damit aus.


find . -maxdepth 1 -type f  -name "*[\:\;><\@\$\#\&\(\)\?\\\/\%]*" '

Findet alle Dateien im aktuellen Verzeichnis, deren Name eines der folgenden Zeichen enthält: :;><@$#&()\/%. Um weitere hinzuzufügen, maskieren Sie sie einfach mit "\" (z. B. "\¿") und fügen Sie sie der Liste in den Klammern ([ ]) hinzu. Wahrscheinlich müssen nicht alle dieser Zeichen maskiert werden, aber ich kann mir nie merken, welche spezielle Variablen in welcher Umgebung sind, also maskiere ich vorsichtshalber alles.

sed 's/\.\///

Entfernt das aktuelle Verzeichnis aus der Ausgabe von find und druckt „foo“ statt „./foo“.

mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\\/\%]/_}

Jedes Mal, wenn dieses kleine Skript wiederholt wird, ist $i der Name einer Datei mit falschem Namen. Dieser Befehl verschiebt (benennt) diese Datei um und ändert alle unerwünschten Zeichen in "_". Weitere Informationen finden Sie unter Bash-Ersetzung.


verwandte Informationen