Wie benenne ich die Erweiterung für eine Reihe von Dateien um?

480

In einem Verzeichnis habe ich eine Reihe von *.htmlDateien. Ich möchte sie alle umbenennen*.txt

Wie kann ich das machen? Ich benutze die Bash-Shell.

bmw0128
quelle

Antworten:

382

Eine bessere Lösung (mit nur Bash-Funktionalität im Gegensatz zu externen Anrufen) finden Sie in einer der anderen Antworten .


Folgendes würde erfordern und nicht erfordern, dass das System das renameProgramm hat (obwohl Sie dies am häufigsten auf einem System haben würden):

for file in *.html; do
    mv "$file" "$(basename "$file" .html).txt"
done

BEARBEITEN: Wie in den Kommentaren erwähnt, funktioniert dies nicht für Dateinamen mit Leerzeichen ohne korrektes Anführungszeichen (jetzt oben hinzugefügt). Wenn Sie nur an Ihren eigenen Dateien arbeiten, von denen Sie wissen, dass sie keine Leerzeichen in den Dateinamen enthalten, funktioniert dies. Wenn Sie jedoch etwas schreiben, das zu einem späteren Zeitpunkt wiederverwendet werden kann, überspringen Sie nicht das richtige Anführungszeichen.

Mikael Auno
quelle
47
Eine Alternative ohne Basisnamen und mit Anführungszeichen: mv "$ {file}" "$ {file /%. Html / .txt}" (siehe man bash, Parametererweiterung für Details)
Rodrigo Queiro
7
Nur gut, wenn sich alle Dateien im aktuellen Verzeichnis befinden, da der Pfadname den Pfadnamen entfernt. Nur eine "Vorsicht"!
Jonathan Leffler
6
Diese Lösung ist schlecht, nicht nur, weil sie langsam ist, sondern weil sie nicht mit Dateinamen mit Leerzeichen funktioniert. Sie sollten IMMER in Bash-Skripten richtig zitieren. mv "$ file" "$ (Basisname" $ ​​file ".html)". txt wäre viel besser. Trotzdem ist mv "$ files" "$ {files% .html} .txt" viel besser.
Balázs Pozsár
8
in Windows tun Sie geraderen *.a *.b
Muhammad Umer
2
Verwenden Sie mindestens die von POSIX angegebene $()Syntax anstelle der alten Backtick-Syntax. Verbessert die Lesbarkeit und macht die Syntax weniger eindeutig, wenn Sie Zeichen haben, für die ein Backslash-Escape erforderlich wäre, um innerhalb der Befehlsersetzung durch letztere wörtlich zu sein.
Charles Duffy
669

Wenn Sie bash verwenden, sind keine externen Befehle wie sed, basename, rename, expr usw. erforderlich.

for file in *.html
do
  mv "$file" "${file%.html}.txt"
done
Ghostdog74
quelle
12
Und wenn Sie die Dateierweiterung nicht kennen, die Sie verwenden können "${file%.*}.txt", kann dies für Dateien ohne Erweiterung gefährlich sein.
Jess
1
Hinweis für alle, die Probleme haben, dies so zu machen, wie ich es getan habe: Beachten Sie, dass sich $in den geschweiften Klammern keine befindet !
Doug65536
5
Ich brauche einen Weg, um diese Antwort dauerhaft zu favorisieren / zu bookmarken, ich erinnere mich nie an die genaue Syntax und
google
7
@danip Das Prozentzeichen-in-Klammer-Konstrukt entfernt Zeichen vom Ende. Es gibt auch ein Hash-in-Bracket-Konstrukt, das Zeichen vom Anfang entfernt. Überprüfen Sie es: tldp.org/LDP/abs/html/parameter-substitution.html#PSUB2
4
Eine andere Antwort auf den Stapelaustausch (die ich nicht finden kann!) Schlug dies vor, verwendete aber auch den --"Operator": mv - "$ file" "$ {file% .html} .txt" Dieser Operator verhindert Dateinamen, die mit beginnen ein '-' von mv als Argumente analysiert.
Rcreswick
191
rename 's/\.html$/\.txt/' *.html

macht genau das, was Sie wollen.

Bernstein
quelle
Ich glaube nicht, dass Sie in Bash einen wörtlichen regulären Ausdruck verwenden können, wie Sie vorschlagen - welche Shell verwenden Sie?
DaveR
1
Ich benutze ein Mac-Terminal
bmw0128
Hier ist die Manpage für die Version von Renunt unter
Amber
Umbenennen ist auf einigen Systemen ein Befehl. Ich habe ein Perl-Skript (ursprünglich aus dem ersten Camel-Buch), das den Job macht. Es gibt auch ein gleichnamiges GNU-Programm, das ungefähr den gleichen Job macht. Mein Mac verfügt nicht über einen vom System bereitgestellten Befehl zum Umbenennen - oder er befindet sich nicht in meinem PATH (der mäßig umfassend ist).
Jonathan Leffler
In Homebrew gibt es eine Umbenennungsformel.
revprez
112

Dies funktionierte für mich unter OSX von .txt bis .txt_bak

find . -name '*.txt' -exec sh -c 'mv "$0" "${0%.txt}.txt_bak"' {} \;
Steven Lizarazo
quelle
4
Funktioniert auch unter Linux.
Diziet
Es ist nicht der Punkt, aber um von .txtzu zu gehen , müssen .txt_bakSie nur verketten _bak;)
corwin.amber
3
Dies ist schön für die rekursive Umbenennung
Leachryanb
Großartig! (unter Ubuntu 16.04) Mein praktischer Anwendungsfall, alle umbenennen .scssin .sass(nach In-Place-Konvertierung…):find . -name '*.scss' -exec sh -c 'mv "$0" "${0%.scss}.sass"' {} \;
Frank Nocke
2
Dies funktionierte mit +6000 Dateien und benannte die gemeldete "Argumentliste war zu lang" um
Tony Cronin
94

Sie möchten verwenden rename:

rename -S .html .txt *.html

Dies ist genau das, was Sie wollen - es wird die Erweiterung ändern aus , .htmlum .txtfür alle Dateien Matching *.html.

Hinweis: Greg Hewgill weist korrekt darauf hin, dass dies keine eingebaute Bash ist. und ist ein separater Linux-Befehl. Wenn Sie nur etwas unter Linux benötigen, sollte dies gut funktionieren. Wenn Sie etwas plattformübergreifenderes benötigen, schauen Sie sich eine der anderen Antworten an.

DaveR
quelle
7
Obwohl dies eine gute Lösung ist, ist das renameProgramm nicht mit bashallen Plattformen verbunden und auch nicht auf allen Plattformen verfügbar. Ich habe es nur unter Linux gesehen.
Greg Hewgill
15
"$ rename .html .txt * .html" führt zu ... einem Syntaxfehler in (eval 1) Zeile 1 in der Nähe von "."
Amber
8
Richtige Syntax ist, rename -S .html .text *.htmlwo -Ssteht für--subst-all
Marek Sebera
8
Brew installieren umbenennen
Nick
4
@ GregHewgill Umbenennung ist für Mac OS mit HomeBrew
CodeBrauer
36

Auf einem Mac ...

  1. Installieren Sie Umbenennen, wenn Sie nicht:brew install rename
  2. rename -S .html .txt *.html
Izilotti
quelle
15

Für Ubuntu-Benutzer:

rename 's/\.html$/\.txt/' *.html
Bheru Lal Lohar
quelle
Dies ist nicht rekursiv, aber es hat bei Ubuntu 14.04 für mich funktioniert.
Max Wallace
9

Dies ist die schickste Lösung, die ich gefunden habe und die unter OSX und Linux funktioniert, und sie funktioniert auch gut mit Git!

find . -name "*.js" -exec bash -c 'mv "$1" "${1%.js}".tsx' - '{}' \;

und mit git:

find . -name "*.js" -exec bash -c 'git mv "$1" "${1%.js}".tsx' - '{}' \;

bdombro
quelle
8

Hier ist ein Beispiel für den Umbenennungsbefehl:

rename -n s/\.htm$/\.html/’ *.htm

Das -n bedeutet, dass es sich um einen Testlauf handelt und keine Dateien geändert werden. Es wird eine Liste der Dateien angezeigt, die umbenannt würden, wenn Sie das -n entfernen würden. Im obigen Fall werden alle Dateien im aktuellen Verzeichnis von einer Dateierweiterung von .htm in .html konvertiert.

Wenn die Ausgabe des obigen Testlaufs in Ordnung aussah, können Sie die endgültige Version ausführen:

rename -v s/\.htm$/\.html/’ *.htm

Das -v ist optional, aber es ist eine gute Idee, es einzuschließen, da es der einzige Datensatz ist, den Sie über Änderungen haben, die mit dem Umbenennungsbefehl vorgenommen wurden, wie in der folgenden Beispielausgabe gezeigt:

$ rename -v 's/\.htm$/\.html/' *.htm
3.htm renamed as 3.html
4.htm renamed as 4.html
5.htm renamed as 5.html

Der schwierige Teil in der Mitte ist eine Perl-Substitution mit regulären Ausdrücken, die unten hervorgehoben wird:

rename -v s/\.htm$/\.html/’ *.htm
AA
quelle
6

In dieser Frage wird Bash ausdrücklich erwähnt, aber wenn Sie ZSH zur Verfügung haben, ist dies ziemlich einfach:

zmv '(*).*' '$1.txt'

Wenn Sie zsh: command not found: zmvdann einfach laufen:

autoload -U zmv

Und dann versuchen Sie es erneut.

Vielen Dank an diesen Originalartikel für den Tipp zu zmv.

Michael Leonard
quelle
4

Nach dem Crawlen der Website einer anderen Person fehlten mir Tausende von Dateien mit der Erweiterung .html in einem breiten Baum von Unterverzeichnissen.

Um sie alle auf einmal umzubenennen, mit Ausnahme der Dateien, die bereits die Erweiterung .html haben (die meisten hatten überhaupt keine), funktionierte dies für mich:

cd wwwroot
find . -xtype f \! -iname *.html   -exec mv -iv "{}"  "{}.html"  \;  # batch rename files to append .html suffix IF MISSING

Im Fall des OP könnte ich das leicht ändern, um nur * .txt-Dateien umzubenennen, wie folgt:

find . -xtype f  -iname *.txt   -exec filename="{}"  mv -iv ${filename%.*}.{txt,html}  \; 

Aufgeschlüsselt (Hammerzeit!):

-iname * .txt
- Bedeutet, dass NUR Dateien berücksichtigt werden, die bereits mit .txt enden

mv -iv "{}. {txt, html}" - Wenn find ein {} als Dateinamen übergibt, extrahiert $ {Dateiname%. *} seinen Basisnamen ohne Erweiterung, um die Parameter für mv zu bilden . bash verwendet {txt, html}, um es als zwei Parameter neu zu schreiben, sodass der letzte Befehl wie folgt ausgeführt wird:mv -iv "filename.txt" "filename.html"

Korrektur erforderlich: Umgang mit Leerzeichen in Dateinamen

Marcos
quelle
4

Der Befehlmmv scheint diese Aufgabe für eine große Anzahl von Dateien (Zehntausende in einer Sekunde) sehr effizient auszuführen. Verwenden Sie beispielsweise Folgendes, um alle .xmlDateien in .htmlDateien umzubenennen :

mmv ";*.xml" "#1#2.html"

Das ;wird mit dem Pfad übereinstimmen, das *wird mit dem Dateinamen übereinstimmen, und diese werden als #1und #2im Ersatznamen bezeichnet.

Antworten auf execoder Pipes waren entweder zu langsam oder schlugen bei einer sehr großen Anzahl von Dateien fehl.

Roko Mijic
quelle
3

Versuche dies

rename .html .txt *.html 

Verwendungszweck:

rename [find] [replace_with] [criteria]
P Sreedhar
quelle
3

Ein bisschen spät zur Party. Sie könnten es mit xargs tun:

ls *.html | xargs -I {} sh -c 'mv $1 `basename $1 .html`.txt' - {}

Oder wenn sich alle Ihre Dateien in einem Ordner befinden

ls folder/*.html | xargs -I {} sh -c 'mv $1 folder/`basename $1 .html`.txt' - {}
insb
quelle
3
Nein, nicht analysierenls . Dieser Befehl ist lächerlich: Er verwendet nutzlos einen Globus mit ls, anstatt den Globus direkt zu verwenden. Dies wird mit Dateinamen unterbrochen, die Leerzeichen, Anführungszeichen und (aufgrund fehlender Anführungszeichen) Glob-Zeichen enthalten.
gniourf_gniourf
Zu Ihrer Information, Ihr verlinkter Artikel enthält eine aktualisierte Notiz, die besagt, dass neuere LS-Dateien "Shell-Escape-Dateien korrekt", wenn sie auf dem Terminal gedruckt werden. Ihr Punkt ist jedoch immer noch eine gute Faustregel.
Katastic Voyage
3

Dies ist eine gute Möglichkeit, mehrere Erweiterungen gleichzeitig zu ändern:

for fname in *.{mp4,avi}
do
   mv -v "$fname" "${fname%.???}.mkv"
done

Hinweis: Achten Sie darauf, dass die Erweiterungsgröße gleich ist (die ???)

Nick De Greek
quelle
2

Schön und einfach!

find . -iname *.html  -exec mv {} "$(basename {} .html).text"  \;
Deano
quelle
2

Wenn Sie PERL bevorzugen, gibt es ein kurzes PERL-Skript (ursprünglich von Larry Wall, dem Erfinder von PERL, geschrieben), das genau das tut, was Sie hier wollen: tips.webdesign10.com/files/rename.pl.txt .

Für Ihr Beispiel sollte Folgendes den Trick tun:

rename.pl 's/html/txt/' *.html
Dudusan
quelle
2
Diese Frage wurde bereits vor langer Zeit beantwortet und akzeptiert, und es scheint nicht, dass Ihre Antwort mehr bringt als das, was bereits gesagt wurde.
ChristopheLec
1
+1, da es sich um ein Larry Wall-Skript handelte (modifiziert von Robin Barker). Die letzte verfügbare URL lautet: tips.webdesign10.com/files/rename.pl.txt
loretoparisi
1

Ähnlich wie zuvor vorgeschlagen, habe ich es so gemacht:

find . -name '*OldText*' -exec sh -c 'mv "$0" "${0/OldText/NewText}"' {} \;

Ich habe zuerst mit validiert

find . -name '*OldText*' -exec sh -c 'echo mv "$0" "${0/OldText/NewText}"' {} \;
Carl Bosch
quelle
1

Eine Zeile, keine Schleifen:

ls -1 | xargs -L 1 -I {} bash -c 'mv $1 "${1%.*}.txt"' _ {}

Beispiel:

$ ls
60acbc4d-3a75-4090-85ad-b7d027df8145.json  ac8453e2-0d82-4d43-b80e-205edb754700.json
$ ls -1 | xargs -L 1 -I {} bash -c 'mv $1 "${1%.*}.txt"' _ {}
$ ls
60acbc4d-3a75-4090-85ad-b7d027df8145.txt  ac8453e2-0d82-4d43-b80e-205edb754700.txt
Christian Bongiorno
quelle
+1 für die Anzeige einer Nur-Bash-Methode, die nicht davon abhängt, ob die vorhandene Erweiterung genau übereinstimmt. Dies funktioniert für jede Eingabeerweiterung, sei es 3 Zeichen lang oder 4 Zeichen lang oder länger
Ciprian Tomoiagă
0

Leider ist es nicht trivial, tragbar zu machen. Du brauchst wahrscheinlich ein bisschen Ausdrucksmagie.

for file in *.html; do echo mv -- "$file" "$(expr "$file" : '\(.*\)\.html').txt"; done

Entfernen Sie das Echo, sobald Sie zufrieden sind, dass es das tut, was Sie wollen.

Bearbeiten: basename ist für diesen speziellen Fall wahrscheinlich etwas besser lesbar, obwohl expres im Allgemeinen flexibler ist.

CB Bailey
quelle
Dies ist vielleicht nicht die beste Antwort auf die Frage, aber es war für mich! Ich brauchte eine Möglichkeit, einen ganzen Pfad nur in einer Zeichenfolge umzubenennen, nicht nur den Dateinamen. Danke fürs Schreiben!
Donut
0

Hier ist, was ich verwendet habe, um .edgeDateien umzubenennen.blade.php

for file in *.edge; do     mv "$file" "$(basename "$file" .edge).blade.php"; done

Funktioniert wie Charme.

Nixon Kosgei
quelle
0

Sie können eine Funktion auch in Bash erstellen, sie hinzufügen .bashrcoder so und sie dann verwenden, wo immer Sie möchten.

change-ext() {
    for file in *.$1; do mv "$file" "$(basename "$file" .$1).$2"; done
}

Verwendungszweck:

change-ext css scss

Quelle des Codes in der Funktion: https://stackoverflow.com/a/1224786/6732111

J Kluseczka
quelle
0

Benennen Sie die Dateierweiterungen für alle Dateien im aktuellen Verzeichnis und in den Unterverzeichnissen ohne andere Pakete um (verwenden Sie nur das Shell-Skript):

  1. Erstellen Sie ein Shell-Skript rename.shim aktuellen Verzeichnis mit dem folgenden Code:

    #!/bin/bash
    
    for file in $(find . -name "*$1"); do
      mv "$file" "${file%$1}$2"
    done
  2. Führen Sie es durch ./rename.sh .old .new.

    Z.B. ./rename.sh .html .txt

Neo Liu
quelle