Benennen Sie mehrere Dateien mit mv um, um die Erweiterung zu ändern

27

Ich möchte Dateien umbenennen, um ihre Erweiterung zu ändern

mv *.txt *.tsv

Aber wenn ich das tue, bekomme ich:

* .tsv ist kein Verzeichnis

Ich finde es etwas seltsam, dass die ersten 10 Google-Hits mvso funktionieren sollten.

Sander Van der Zeeuw
quelle
Sie sollten erklären, wie Sie diese Dateien genau umbenennen möchten.
Totor
1
Nun, ich habe Dateien mit der Erweiterung * .gappedPeak und möchte sie in * .bed umbenennen. sie befinden sich alle im selben Verzeichnis, es sollte sehr einfach sein, aber eine vollständige for-Schleife war erforderlich, damit ich erfolgreich war
Sander Van der Zeeuw
Was Sie bei Google gefunden haben, gilt meiner Meinung nach für MSDOS.
Tiktak
Die alternative Lösung von @devnull ist wirklich hilfreich
lucasvw

Antworten:

22

Wenn Sie den Befehl ausgeben:

mv *.txt *.tsv

Nehmen wir an, die Shell erweitert die Platzhalter, wenn übereinstimmende Dateien (einschließlich Verzeichnisse) vorhanden sind. Die Liste der Dateien wird hier an das Programm übergeben mv. Wenn keine Übereinstimmungen gefunden werden, wird die nicht erweiterte Version übergeben.

Nochmals: Die Shell erweitert die Muster, nicht das Programm.


Viele Beispiele sind vielleicht der beste Weg, also los geht's:

Beispiel 1:

$ ls
file1.txt file2.txt

$ mv *.txt *.tsv

Nun , was auf das geschieht , mvist , dass die Shell erweitert *.txtmit den entsprechenden Dateien. Da gibt es keine *.tsvDateien, die nicht geändert werden.

Der mvBefehl wird mit zwei speziellen Argumenten aufgerufen :

  • argc: Anzahl der Argumente, einschließlich des Programms.
  • argv: Ein Array von Argumenten, einschließlich des Programms als ersten Eintrag.

Im obigen Beispiel wäre das:

 argc = 4
 argv[0] = mv
 argv[1] = file1.txt
 argv[2] = file2.txt
 argv[3] = *.tsv

Das mvProgramm prüft, ob das letzte Argument *.tsvein Verzeichnis ist. Da dies nicht der Fall ist, kann das Programm nicht fortgesetzt werden, da es nicht zum Verketten von Dateien vorgesehen ist. (Verschieben Sie in der Regel alle Dateien in eine.) Erstellen Sie keine Verzeichnisse aus einer Laune heraus.

Als Ergebnis bricht es ab und meldet den Fehler:

mv: target ‘*.tsv’ is not a directory

Beispiel 2:

Nun, wenn Sie stattdessen sagen:

$ mv *1.txt *.tsv

Der mvBefehl wird ausgeführt mit:

 argc = 3
 argv[0] = mv
 argv[1] = file1.txt
 argv[2] = *.tsv

mvÜberprüfen Sie nun erneut, ob *.tsvvorhanden. Da dies nicht der Fall ist, wird die Datei file1.txtnach verschoben *.tsv. Das heißt: Die Datei wird in *.tsvmit dem Stern und allem umbenannt.

$ mv *1.txt *.tsv
‘file1.txt’ -> ‘*.tsv’

$ ls
file2.txt *.tsv

Beispiel 3:

Wenn Sie stattdessen sagten:

$ mkdir *.tsv
$ mv *.txt *.tsv

Der mvBefehl wird ausgeführt mit:

 argc = 3
 argv[0] = mv
 argv[1] = file1.txt
 argv[1] = file2.txt
 argv[2] = *.tsv

Da es sich *.tsvnun um ein Verzeichnis handelt, werden die Dateien dorthin verschoben.


Nun: Mit Befehlen wie some_command *.tsvwenn die Absicht besteht, den Platzhalter tatsächlich beizubehalten, sollte man ihn immer zitieren. Durch das Zitieren verhindern Sie, dass die Platzhalter erweitert werden, falls Übereinstimmungen auftreten sollten. ZB sagen mkdir "*.tsv".

Beispiel 4:

Die Erweiterung kann weiterhin angezeigt werden, wenn Sie beispielsweise Folgendes tun:

$ ls
file1.txt file2.txt

$ mkdir *.txt
mkdir: cannot create directory ‘file1.txt’: File exists
mkdir: cannot create directory ‘file2.txt’: File exists

Beispiel 5:

Jetzt: Der mvBefehl kann und kann mit mehreren Dateien arbeiten. Wenn es aber mehr als zwei gibt, muss das letzte ein Zielverzeichnis sein. (Optional können Sie die -t TARGET_DIROption zumindest für GNU mv verwenden.)

Das ist also OK:

$ ls -F
b1.tsv  b2.tsv  f1.txt  f2.txt  f3.txt  foo/

$ mv *.txt *.tsv foo

Hier mvwürde aufgerufen werden mit:

 argc = 7
 argv[0] = mv
 argv[1] = b1.tsv
 argv[2] = b2.tsv
 argv[3] = f1.txt
 argv[4] = f2.txt
 argv[5] = f3.txt
 argv[6] = foo

und alle Dateien landen im Verzeichnis foo.


Wie für Ihre Links. Sie haben eine (in einem Kommentar) angegeben, wo überhaupt mvnicht erwähnt wird, aber rename. Wenn Sie mehr Links haben, können Sie diese teilen. Dies gilt auch für Manpages, auf denen Sie behaupten, dass dies zum Ausdruck gebracht wird.

Runium
quelle
30

Ich weiß, dass dies Ihre Frage nicht beantwortet, aber falls Sie nach einer anderen Möglichkeit suchen, die Dateien im Vergleich zu Ihrer Umgehungsschleife umzubenennen, warum nicht find? Ich habe diesen Befehl oft verwendet, um Dateierweiterungen in großen Verzeichnissen durch Hunderttausende von Dateien zu ersetzen. Dies sollte auf jedem POSIX-kompatiblen System funktionieren:

find . -name "*.gappedPeak" -exec sh -c 'mv "$1" "${1%.gappedPeak}.bed"' _ {} \;

Befehlsaufschlüsselung:

  1. ' .' => Suchpfad ab aktuellem Verzeichnis mit '. '

  2. -name=> find match name setzen (in diesem Fall alle Dateien, die mit enden .gappedPeak)

  3. -exec => führe bei jedem Treffer den folgenden Befehl aus

  4. sh -c => 'exec' erstellt für jede Übereinstimmung eine unabhängige Shell-Umgebung

  5. mv "$1" "${1%.gappedPeak}.bed"=> mverste Variable (bezeichnet mit $ 1 ), die der aktuelle Dateiname ist, zu neuem Namen. Hier mache ich einen Teilstring-Abgleich und lösche; Nehmen Sie also erneut die erste Variable, $ 1, und verwenden Sie %, um sie .gappedPeakaus der Zeichenfolge zu löschen . Die .bedam Ende verkettet nur die verbleibende Variable, die jetzt nur mit den neuen zu schaffen Dateinamen.test#.bedtest#.bed

  6. Der Unterstrich ist ein Platzhalter für $ 0

  7. Das {}wird durch jeden ( *.gappedPeak) Dateinamen ersetzt, den der findBefehl gefunden hat, und wird zu $ 1 für den shBefehl.

  8. \;markiert das Ende des -execBefehls. Sie können auch ';'oder verwenden ";".

Beispiel:

[user@before]# ls -lh
total 0
-rw-r--r--. 1 root root 0 Jan 26 11:40 test1.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test2.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test3.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test4.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test5.gappedPeak

[user@after]# ls -lh
total 0
-rw-r--r--. 1 root root 0 Jan 26 11:40 test1.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test2.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test3.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test4.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test5.bed
devnull
quelle
Könnten Sie den Befehl durchgehen und beschreiben, was die einzelnen Teile tun?
user1717828
Es tut mir leid, ich habe meinen Beitrag aktualisiert. Hoffentlich hilft das.
Devnull
1
Super, danke! Mit einer Bash-Anleitung und Ihrer Erklärung konnte ich alles bekommen.
user1717828
Kein Problem. Froh, dass es hilft.
Devnull
Klappt wunderbar. Hier ist ein weiteres vereinfachtes Beispiel für file.abc-> blub.xyzin mehreren Unterverzeichnissen:find . -name "file.abc" -exec sh -c 'mv "$1" "$(dirname $1)/blub.xyz"' _ {} \;
Mahn
9

mv *.txt *.tsvfunktioniert nicht; mvkann jeweils nur eine Datei umbenennen. Sie haben die Erklärungen entweder falsch verstanden oder sie sind falsch.

mmvund renamekann mehrere Dateien gleichzeitig umbenennen. Es gibt jedoch zwei Versionen von, renamedie unterschiedlich bezeichnet werden. Es sollte hier viele Fragen dazu geben.

Hauke ​​Laging
quelle
1
cyberciti.biz/tips/… Der erste Treffer bei Google ist, dass MV auch funktionieren sollte. Deshalb fand ich es so seltsam
Sander Van der Zeeuw
3
@SanderVanderZeeuw Ich weiß nicht, was du da liest. Die Beispiele verwenden rename, nicht mv.
Hauke ​​Laging
1
Entschuldigung, ich habe das falsche HTML eingefügt. Dies war der einzige udemy.com/blog/rename-a-file-in-linux
Sander Van der Zeeuw
3
@SanderVanderZeeuw Peinlich. Diese Leute bieten Kurse an? Leider sehe ich dort keine Kontaktmöglichkeit. Sie können leicht überprüfen, ob dies funktioniert. Aber in mv *.txt *.tsv mv(normalerweise) nicht sehen *.txtoder *.tsvaber die Shell-erweiterten Dateinamen. Die Anzahl der Dateien, auf die diese Platzhalterzeichen erweitert werden, ist "zufällig". Dies funktioniert nur, wenn eine Datei mit dem Namen vorhanden *.txtist, der (wörtlich) umbenannt werden soll *.tsv(ohne Anführungszeichen darf die bashOption nullglobnicht gesetzt sein).
Hauke ​​Laging
1
Oder schlimmer. Wenn man eine Datei mit dem Namen eg foo.txtund eine mit dem Namen baz.tsvthe hat, mv *.txt *.tsvwird die vorhandene .tsvDatei überschrieben ...
Runium
4

Wenn Sie beispielsweise asd.txtund qwe.txtDateien im Verzeichnis haben, während Sie den Befehl ausführen mv *.txt *.tsv, wird versucht, diese beiden Dateien in ein Verzeichnis mit dem Namen zu verschieben *.tsv. Da es kein solches Verzeichnis gibt, wird ein Fehler ausgegeben.

Esref
quelle
Danke, das klärt teilweise. Trotzdem finde ich es seltsam, dass ich so viele Handbuchseiten sehe, in denen behauptet wird, ich sollte an mehreren arbeiten.
Sander Van der Zeeuw
2

rename(1)

renameist ein Perl-Skript von Larry Wall, dem Hersteller von Perl. Es benötigt einen Perl-Regex und verarbeitet den Dateinamen.

rename 's/\.txt$/.tsv/' *.txt

Installation

Debian / Ubuntu

Wenn Sie renameunter Debian / Ubuntu installieren müssen, können Sie dies tun

sudo apt install rename
Evan Carroll
quelle
0

Eine weitere Option ist die Verwendung von:

cp -p *.txt *.tsv
rm -f *.txt
  • In der ersten Zeile werden alle *.txtDateien nach kopiert , *.tsvwobei ihre Attribute mit dem -pFlag beibehalten werden.
  • Die zweite Zeile entfernt alle Dateien mit dem Muster *.txt
  • Diese Methode erfordert, dass Sie über genügend Speicherplatz verfügen, um die Quell- und Zieldateien vorübergehend zu speichern
  • Diese Methode ist langsamer als mvdie, mit der einfach / directory / filename geändert wird, ohne die Dateien tatsächlich zu verschieben, es sei denn, sie befinden sich auf einer anderen Partition.
WinEunuuchs2Unix
quelle