GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Konvertieren Sie alle Dateierweiterungen in Kleinbuchstaben

Ich habe mit diesem Befehl Erfolg.

rename JPG jpg *.JPG

Wobei rename ist ein Befehl, der die Shell anweist, jedes Vorkommen von JPG umzubenennen bis jpg im aktuellen Ordner mit allen Dateinamen mit der Erweiterung JPG .

Wenn Sie sehen, dass Bareword "JPG" nicht erlaubt ist, während "strict subs" in (eval 1) Zeile 1 mit diesem Ansatz verwendet wird, versuchen Sie Folgendes:

rename 's/\.JPG$/.jpg/' *.JPG

Lösung

Sie können die Aufgabe in einer Zeile lösen:

find . -name '*.*' -exec sh -c '
  a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/");
  [ "$a" != "$0" ] && mv "$0" "$a" ' {} \;

Hinweis:Dies bricht bei Dateinamen, die Zeilenumbrüche enthalten. Aber ertragen Sie mich erst einmal.

Anwendungsbeispiel

$ mkdir C; touch 1.TXT a.TXT B.TXT C/D.TXT
$ find .
.
./C
./C/D.TXT
./1.TXT
./a.TXT
./B.TXT

$ find . -name '*.*' -exec sh -c 'a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/"); [ "$a" != "$0" ] && mv "$0" "$a" ' {} \;

$ find .
.
./C
./C/D.txt
./a.txt
./B.txt
./1.txt

Erklärung

Sie finden alle Dateien im aktuellen Verzeichnis (. ) mit dem Punkt . in seinem Namen (-name '*.*' ) und führen Sie den Befehl für jede Datei aus:

a=$(echo "$0" | sed -r "s/([^.]*)\$/\L\1/");
[ "$a" != "$0" ] && mv "{}" "$a"

Dieser Befehl bedeutet:Versuchen Sie, die Dateierweiterung in Kleinbuchstaben umzuwandeln (das macht sed ):

$ echo 1.txt | sed -r "s/([^.]*)\$/\L\1/"
1.txt
$ echo 2.TXT | sed -r "s/([^.]*)\$/\L\1/"
2.txt

und speichern Sie das Ergebnis in a Variable.

Wenn etwas geändert wurde [ "$a" != "$0" ] , benennen Sie die Datei um mv "$0" "$a" .

Der Name der verarbeiteten Datei ({} ) an sh -c übergeben als zusätzliches Argument und wird in der Befehlszeile als $0 angezeigt .Es macht das Skript sicher, denn in diesem Fall nimmt die Shell {} als Daten, nicht als Code-Teil, wie wenn es direkt in der Befehlszeile angegeben wird. (Danke @gniourf_gniourf für den Hinweis auf dieses wirklich wichtige Thema ).

Wie Sie sehen können, wenn Sie {} verwenden Direkt im Skript ist es möglich, einige Shell-Injektionen in den Dateinamen zu haben, etwa so:

; rm -rf * ;

In diesem Fall wird die Injektion von der Shell als Teil des Codes betrachtet und ausgeführt.

While-Version

Klarere, aber etwas längere Version des Skripts:

find . -name '*.*' | while IFS= read -r f
do
  a=$(echo "$f" | sed -r "s/([^.]*)\$/\L\1/");
  [ "$a" != "$f" ] && mv "$f" "$a"
done

Dies bricht immer noch für Dateinamen, die Zeilenumbrüche enthalten. Um dieses Problem zu beheben, benötigen Sie einen find das -print0 unterstützt (wie GNU find ) und Bash (damit read unterstützt den -d Trennschalter):

find . -name '*.*' -print0 | while IFS= read -r -d '' f
do
  a=$(echo "$f" | sed -r "s/([^.]*)\$/\L\1/");
  [ "$a" != "$f" ] && mv "$f" "$a"
done

Dies bricht immer noch für Dateien, die abschließende Zeilenumbrüche enthalten (da sie von a=$(...) absorbiert werden Unterschale. Wenn Sie wirklich wollen eine narrensichere Methode (und das sollten Sie!), mit einer aktuellen Version von Bash (Bash≥4.0), die den ,, unterstützt Parametererweiterung hier ist die ultimative Lösung:

find . -name '*.*' -print0 | while IFS= read -r -d '' f
do
  base=${f%.*}
  ext=${f##*.}
  a=$base.${ext,,}
  [ "$a" != "$f" ] && mv -- "$f" "$a"
done

Zurück zur ursprünglichen Lösung

Oder in einem find go (zurück zur ursprünglichen Lösung mit einigen Korrekturen, die es wirklich narrensicher machen):

find . -name '*.*' -type f -exec bash -c 'base=${0%.*} ext=${0##*.} a=$base.${ext,,}; [ "$a" != "$0" ] && mv -- "$0" "$a"' {} \;

Ich habe -type f hinzugefügt sodass nur normale Dateien umbenannt werden. Ohne dies könnten Sie immer noch Probleme haben, wenn Verzeichnisnamen vor Dateinamen umbenannt werden. Wenn Sie auch Verzeichnisse (und Links, Pipes usw.) umbenennen möchten, sollten Sie -depth verwenden :

find . -depth -name '*.*' -type f -exec bash -c 'base=${0%.*} ext=${0##*.} a=$base.${ext,,}; [ "$a" != "$0" ] && mv -- "$0" "$a"' {} \;

damit find führt eine Tiefensuche durch.

Sie können argumentieren, dass es nicht effizient ist, einen bash zu spawnen Prozess für jede gefundene Datei. Das ist richtig, und die vorherige Loop-Version wäre dann besser.


Dies ist kürzer, aber allgemeiner, kombiniert aus der Antwort anderer:

rename 's/\.([^.]+)$/.\L$1/' *

Simulation

Verwenden Sie für die Simulation -n , also rename -n 's/\.([^.]+)$/.\L$1/' * . Auf diese Weise können Sie sehen, was geändert wird, bevor die tatsächlichen Änderungen durchgeführt werden. Beispielausgabe:

Happy.Family.GATHERING.JPG renamed as Happy.Family.GATHERING.jpg
Hero_from_The_Land_Across_the_River.JPG renamed as Hero_from_The_Land_Across_the_River.jpg
rAnD0m.jPg1 renamed as rAnD0m.jpg1

Kurze Erklärung zur Syntax

  • Die Syntax ist rename OPTIONS 's/WHAT_TO_FIND_IN_THE_NAME/THE_REPLACEMENT/' FILENAMES
  • \.([^.]+)$ bedeutet eine Folge von allem außer Punkt ([^.] ) am Ende der Zeichenfolge ($ ), nach dem Punkt (\. )
  • .\L$1 bedeutet Punkt (\. ) gefolgt von Kleinbuchstaben (\L ) von 1 Gruppe ($1 )
  • Die erste Gruppe ist in diesem Fall die Erweiterung ([^.]+ )
  • Verwenden Sie besser einfache Anführungszeichen ' anstelle von doppelten Anführungszeichen " um die Regex zu umschließen, um Shell-Expansion zu vermeiden

Linux
  1. Wie bereinigt man Dateierweiterungen?

  2. Alle Dateien bis zum Match anzeigen?

  3. In .txt-Datei schreiben?

  4. Ändern aller Dateierweiterungen in einem Ordner mit CLI in Linux

  5. ldapsearch passwortdateiformat

Benennen Sie eine Datei im Linux-Terminal um

So entfernen Sie alle Dateien in einem Ordner außer einer bestimmten Datei in Linux

So konvertieren Sie eine Windows-Datei in eine UNIX-Datei

Alle Ausgaben mit Bash unter Linux in eine Datei umleiten?

Konvertieren Sie .txt in .csv in der Shell

Wie konvertiere ich tar.bz2 in tar.gz?