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 mv
so funktionieren sollten.
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 mv
so funktionieren sollten.
Antworten:
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:
$ ls
file1.txt file2.txt
$ mv *.txt *.tsv
Nun , was auf das geschieht , mv
ist , dass die Shell erweitert *.txt
mit den entsprechenden Dateien. Da gibt es keine *.tsv
Dateien, die nicht geändert werden.
Der mv
Befehl 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 mv
Programm prüft, ob das letzte Argument *.tsv
ein 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
Nun, wenn Sie stattdessen sagen:
$ mv *1.txt *.tsv
Der mv
Befehl wird ausgeführt mit:
argc = 3
argv[0] = mv
argv[1] = file1.txt
argv[2] = *.tsv
mv
Überprüfen Sie nun erneut, ob *.tsv
vorhanden. Da dies nicht der Fall ist, wird die Datei file1.txt
nach verschoben *.tsv
. Das heißt: Die Datei wird in *.tsv
mit dem Stern und allem umbenannt.
$ mv *1.txt *.tsv
‘file1.txt’ -> ‘*.tsv’
$ ls
file2.txt *.tsv
Wenn Sie stattdessen sagten:
$ mkdir *.tsv
$ mv *.txt *.tsv
Der mv
Befehl wird ausgeführt mit:
argc = 3
argv[0] = mv
argv[1] = file1.txt
argv[1] = file2.txt
argv[2] = *.tsv
Da es sich *.tsv
nun um ein Verzeichnis handelt, werden die Dateien dorthin verschoben.
Nun: Mit Befehlen wie some_command *.tsv
wenn 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"
.
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
Jetzt: Der mv
Befehl 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_DIR
Option 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 mv
wü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 mv
nicht 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.
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:
'
.
' => Suchpfad ab aktuellem Verzeichnis mit '. '
-name
=> find match name setzen (in diesem Fall alle Dateien, die mit enden.gappedPeak
)
-exec
=> führe bei jedem Treffer den folgenden Befehl aus
sh -c
=> 'exec' erstellt für jede Übereinstimmung eine unabhängige Shell-Umgebung
mv "$1" "${1%.gappedPeak}.bed"
=>mv
erste 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.gappedPeak
aus der Zeichenfolge zu löschen . Die.bed
am Ende verkettet nur die verbleibende Variable, die jetzt nur mit den neuen zu schaffen Dateinamen.test#
.bed
test#.bed
Der Unterstrich ist ein Platzhalter für $ 0
Das
{}
wird durch jeden (*.gappedPeak
) Dateinamen ersetzt, den derfind
Befehl gefunden hat, und wird zu $ 1 für densh
Befehl.
\;
markiert das Ende des-exec
Befehls. 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
file.abc
-> blub.xyz
in mehreren Unterverzeichnissen:find . -name "file.abc" -exec sh -c 'mv "$1" "$(dirname $1)/blub.xyz"' _ {} \;
mv *.txt *.tsv
funktioniert nicht; mv
kann jeweils nur eine Datei umbenennen. Sie haben die Erklärungen entweder falsch verstanden oder sie sind falsch.
mmv
und rename
kann mehrere Dateien gleichzeitig umbenennen. Es gibt jedoch zwei Versionen von, rename
die unterschiedlich bezeichnet werden. Es sollte hier viele Fragen dazu geben.
rename
, nicht mv
.
mv *.txt *.tsv
mv
(normalerweise) nicht sehen *.txt
oder *.tsv
aber 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 *.txt
ist, der (wörtlich) umbenannt werden soll *.tsv
(ohne Anführungszeichen darf die bash
Option nullglob
nicht gesetzt sein).
foo.txt
und eine mit dem Namen baz.tsv
the hat, mv *.txt *.tsv
wird die vorhandene .tsv
Datei überschrieben ...
Wenn Sie beispielsweise asd.txt
und qwe.txt
Dateien 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.
rename(1)
rename
ist 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
Wenn Sie rename
unter Debian / Ubuntu installieren müssen, können Sie dies tun
sudo apt install rename
Eine weitere Option ist die Verwendung von:
cp -p *.txt *.tsv
rm -f *.txt
*.txt
Dateien nach kopiert , *.tsv
wobei ihre Attribute mit dem -p
Flag beibehalten werden.*.txt
mv
die, 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.