Ich habe versehentlich vergessen, das Ziel anzugeben, bevor ich die Eingabetaste gedrückt habe. Wohin werden mv ./*ohne Angabe eines Ziels die Dateien und Verzeichnisse unter dem aktuellen Verzeichnis verschoben?
"Ich bin überrascht, dass mv1 Argument akzeptiert wird." Es akzeptiert alle Argumente, die die Shell nach dem Erweitern des Befehls übergeben hat *.
Glglgl
Antworten:
41
Wenn das letzte Argument ein Verzeichnis war, haben Sie einfach alle Dateien und Verzeichnisse in Ihrem aktuellen Arbeitsverzeichnis (mit Ausnahme derjenigen, deren Namen mit Punkten beginnen) in dieses Verzeichnis verschoben. Wenn zwei Dateien vorhanden waren, hat die erste Datei möglicherweise die zweite Datei überschrieben.
Hier sind einige Demonstrationen:
Mehr als zwei Dateien und das letzte Argument ist eine Datei
$ mkdir d1 d2 d3
$ touch a b c e
$ mv *
mv: target 'e' is not a directory
Mehr als zwei Dateien und das letzte Argument ist ein Verzeichnis
$ mkdir d1 d2 d3
$ touch a b c
$ mv -v *
'a' -> 'd3/a'
'b' -> 'd3/b'
'c' -> 'd3/c'
'd1' -> 'd3/d1'
'd2' -> 'd3/d2'
Zwei Akten
$ touch a b
$ mv -v *
'a' -> 'b'
Weitere Erklärung
Die Shell erweitert das glob ( *) zu Argumenten für mv. Der Glob wird normalerweise in alphabetischer Reihenfolge erweitert. mvsieht immer eine Liste von Dateien und Verzeichnissen. Es sieht nie den Globus selbst.
Der Befehl mvunterstützt zwei Arten des Verschiebens. Eins ist mv file ... directory. Der andere ist mv old-file-name new-file-name(oder mv old-file-name directory/new-file-name).
Zuerst mache ich eine Testbasis - 5 Dateien und einen Ordner:
touch file1 file2 file3 file4 file5
mkdir folder
Als nächstes führe ich einen Testbefehl aus. Die -vOption gibt an, dass jeder Befehl, den die Shell ausführt, gedruckt werden soll stderr. Die -xOption gibt an, dass dasselbe gedruckt werden soll stderr- dies soll jedoch erfolgen, nachdem der Befehl ausgewertet wurde, aber bevor die Shell ihn ausführt.
Sie sehen also, dass der Befehl, den ich der Shell übergebe, echo mv *und der Befehl, den die Shell ausführt, nachdem sie* erweitert wurde, echo mvvon all diesen Dateien und dem Ordner gefolgt wird.
Standardmäßig erweitert die Shell Globs wie folgt :
Wenn Sie also einen Befehl in einer Shell ausführen, die mit Standardoptionen wie mv *der Shell konfiguriert ist, wird *eine Argumentliste aller Dateien im aktuellen Verzeichnis in das Wort eingeblendet, sortiert nach Ländereinstellung. Es führt den Syscall exec(ve)für mv(im Wesentlichen) mit dieser angehängten Argumentliste aus. mvErhält also alle Argumente, während die Shell sie sortiert. Neben stracediesen Effekten können Sie das Debug-Out wie folgt erneut verwenden:
sh -s -- mv * <<\SCRIPT
sed -n l /proc/$$/cmdline
echo "$@"
SCRIPT
Grundsätzlich wird die Shell mvmit dem Inhalt des Verzeichnisses (wenn es nicht leer ist und keine Dateien / Ordner enthält, deren Namen mit "" beginnen .) als Argumentliste ausgeführt. mvwird POSIX angegeben, um sein letztes Argument als Verzeichnis zu interpretieren, wenn es mit mehr als zwei Argumenten aufgerufen wird - auf dieselbe Weise lnwie (weil es sich in der zugrunde liegenden Funktion tatsächlich um unglaublich ähnliche Tools handelt) .
In der ersten Synopse verschiebt das mvDienstprogramm die vom Operanden source_file angegebene Datei in das von target_file angegebene Ziel . Diese erste Zusammenfassungsform wird angenommen, wenn der letzte Operand kein vorhandenes Verzeichnis benennt und kein symbolischer Link ist, der auf ein vorhandenes Verzeichnis verweist. Wenn in diesem Fall Quellendateinamen einer Nicht-Verzeichnisdatei und Zieldatei mit einem nachgestellten /slashZeichen enden , mvwird dies als Fehler behandelt, und es werden keine Quellendatei- Operanden verarbeitet.
mvVerschiebt in der zweiten Zusammenfassungsform jede Datei, die von einem Quellendatei- Operanden benannt wurde, in eine Zieldatei im vorhandenen Verzeichnis, das vom Operanden Zielverzeichnis benannt wurde , oder verweist darauf, wenn Zielverzeichnis eine symbolische Verknüpfung ist, die auf ein vorhandenes Verzeichnis verweist. Der Zielpfad für jede Quellendatei besteht aus der Verkettung des Zielverzeichnisses, einem einzelnen /slashZeichen, wenn das Ziel nicht auf a endete /slash, und der letzten Pfadname-Komponente der Quellendatei . Diese zweite Form wird angenommen, wenn der letzte Operand ein vorhandenes Verzeichnis benennt.
Also, wenn *erweitert um:
zwei Dateien
Sie sollten nur eine Datei haben, die von der ersten renamedzur zweiten nach der zweiten gehört unlinked.
Eine oder mehrere Dateien, gefolgt von einem Verzeichnis oder einem Link zu einer
Sie sollten nur ein Verzeichnis oder einen Link zu einem haben, in das der gesamte vorherige Inhalt der Eltern gerade verschoben wurde.
noch etwas
Sie sollten eine Fehlermeldung und einen befriedigenden Seufzer der Erleichterung haben.
Ja, mit dem alten shDing habe ich das Debuggen vergessen, aber in Bezug auf meine ursprüngliche Frage bedeutet es, dass das Problem nicht die Shell ist mv? Das ist böse, es ist einfacher als ich ursprünglich dachte, aber es ist eine echte Falle.
user2485710
5
@ user2485710, der entscheidende Punkt ist, dass in Unix die Shell für das Erweitern von Platzhaltern verantwortlich ist, bevor die Befehlszeilenargumente an den Befehl übergeben werden. In Windows muss jeder Befehl Platzhalter selbst erweitern. Auf diese Weise können Unix-Shells erweiterte Platzhalterfunktionen anbieten, die mit jedem Befehl funktionieren.
cjm
2
@mikeserv Angesichts der Tatsache, dass diese Dateien nicht so wichtig waren, habe ich mich beeilt, aufzuräumen und mit dem nächsten Schritt fortzufahren, aber ich kann die Dinge bestätigen, wie sie jetzt in meiner Bearbeitung meines ersten Posts / meiner ersten Frage erscheinen.
user2485710
6
@mikeserv tl; dr, *ist das nicht ein einziges argument? Recht? :)
Bernhard
1
@Bernhard - das ist der einzige Fall, den ich nicht behandelt habe - weil es sein könnte .
mikeserv
18
Zuerst wird die Shell ./*auf alle Dateien im aktuellen Verzeichnis erweitert (außer Dateien, die mit einem Punkt beginnen).
Wenn es keine oder nur eine Datei gibt: mvschlägt fehl
wenn es zwei dateien gibt: die erste wird in die zweite verschoben (die gehen also verloren)
Wenn es mehr als zwei Dateien gibt:
Wenn das letzte Verzeichnis ein Verzeichnis ist: Alle Dateien werden in dieses Verzeichnis verschoben
Vielen Dank. Wie kann man feststellen, welches Unterverzeichnis "das letzte" ist?
Tim
7
Rufen Sie echo ./*einfach an und sehen Sie, welche Reihenfolge Ihre Shell verwendet (normalerweise alphabetisch).
Jofel
Wenn es mit einer Datei fehlschlägt, warum sagt es das nicht?
Noumenon
@Noumenon Ich verstehe deinen Kommentar nicht. mvGibt eine Fehlermeldung zurück, wenn sie nur mit einem Argument aufgerufen wird.
Jofel
Du hast recht. Das gleiche Kommando aus meiner Geschichte gibt missing destination file operand after *filename*es jetzt , obwohl es gestern nicht geschah.
Noumenon
4
Bei der Eingabe mv ./*wird Ihre Shell ./*vor der Ausführung erweitert mv.
Ein paar Dinge zu beachten:
Wenn ./*in weniger als 2 Argumente erweitert mvwird, wird logischerweise ein Fehler erzeugt.
./* wird normalerweise in jede Datei (einschließlich Verzeichnis) erweitert, die im aktuellen Verzeichnis vorhanden ist und nicht mit einem Punkt beginnt.
Sie können steuern, in was ./*erweitert wird, indem Sie die Dokumentation Ihrer Shell lesen ( man 7 globist ein Einstiegspunkt in das Thema). Unterschiedliche Shells haben unterschiedliche Optionen.
Die Shell erweitert den Platzhalter *zu einer Liste mit Verzeichnisinhalten. Dann übergibt die Shell diese vollständige Liste an den Befehl. Der Befehl sieht nie *.
Der Befehl mv file1 file2 ... filen directoryverschiebt file1 ... filen in das Verzeichnis.
Beispiel
Hier erstelle ich ein Testverzeichnis mit drei Dateien
$ mkdir t
$ cd t
$ echo a>a; echo b>b; echo c>c
$ ls
a b c
Sie können nicht mehrere Dateien in eine einzige Datei verschieben
$ mv *
mv: target `c' is not a directory
Fügen wir ein Unterverzeichnis hinzu
$ mkdir d
Sie können mehrere Dateien in ein Unterverzeichnis verschieben
Es mv file1 file2 ... filen directoryist sehr unwahrscheinlich, dass der Befehl überhaupt etwas damit zu tun hat *.
mikeserv
@ Mike: Meine Antwort weist darauf hin, dass die letzte Stufe der Shell-Erweiterung letztere effektiv in erstere umwandelt. Nicht zu wissen, scheint die Ursache für die Verwirrung des OP zu sein.
RedGrittyBrick
Ja, aber ich gehe davon aus, dass die Shell nicht erweitert *werden würde, es file dirsei denn, es gibt ein Gebietsschema, in dem dFolgendes folgt f.
mikeserv
@mikeserv: Es gibt so ein Gebietsschema, mein Beispiel ist ein Ausschneiden und Einfügen von Putty, das eine Verbindung zu einem CentOS 5.6 GNU / Linux-System herstellt.
RedGrittyBrick
welches Gebietsschema ist das? Dein Beispiel ist a b c ddas, was nicht ist file ... dir. Ich habe überhaupt nur kommentiert, weil Sie die Sorte nirgendwo erwähnen und sagen, nur das *wird file ... dirwas nicht passiert.
mv
1 Argument akzeptiert wird." Es akzeptiert alle Argumente, die die Shell nach dem Erweitern des Befehls übergeben hat*
.Antworten:
Wenn das letzte Argument ein Verzeichnis war, haben Sie einfach alle Dateien und Verzeichnisse in Ihrem aktuellen Arbeitsverzeichnis (mit Ausnahme derjenigen, deren Namen mit Punkten beginnen) in dieses Verzeichnis verschoben. Wenn zwei Dateien vorhanden waren, hat die erste Datei möglicherweise die zweite Datei überschrieben.
Hier sind einige Demonstrationen:
Mehr als zwei Dateien und das letzte Argument ist eine Datei
Mehr als zwei Dateien und das letzte Argument ist ein Verzeichnis
Zwei Akten
Weitere Erklärung
Die Shell erweitert das glob (
*
) zu Argumenten fürmv
. Der Glob wird normalerweise in alphabetischer Reihenfolge erweitert.mv
sieht immer eine Liste von Dateien und Verzeichnissen. Es sieht nie den Globus selbst.Der Befehl
mv
unterstützt zwei Arten des Verschiebens. Eins istmv file ... directory
. Der andere istmv old-file-name new-file-name
(odermv old-file-name directory/new-file-name
).quelle
Zuerst mache ich eine Testbasis - 5 Dateien und einen Ordner:
Als nächstes führe ich einen Testbefehl aus. Die
-v
Option gibt an, dass jeder Befehl, den die Shell ausführt, gedruckt werden sollstderr
. Die-x
Option gibt an, dass dasselbe gedruckt werden sollstderr
- dies soll jedoch erfolgen, nachdem der Befehl ausgewertet wurde, aber bevor die Shell ihn ausführt.AUSGABE
Sie sehen also, dass der Befehl, den ich der Shell übergebe,
echo mv *
und der Befehl, den die Shell ausführt, nachdem sie*
erweitert wurde,echo mv
von all diesen Dateien und dem Ordner gefolgt wird.Standardmäßig erweitert die Shell Globs wie folgt :
AUSGABE
Dies ist ein Ergebnis der
set [+-]f
Glob-Funktion:AUSGABE
Wenn Sie also einen Befehl in einer Shell ausführen, die mit Standardoptionen wie
mv *
der Shell konfiguriert ist, wird*
eine Argumentliste aller Dateien im aktuellen Verzeichnis in das Wort eingeblendet, sortiert nach Ländereinstellung. Es führt den Syscallexec(ve)
fürmv
(im Wesentlichen) mit dieser angehängten Argumentliste aus.mv
Erhält also alle Argumente, während die Shell sie sortiert. Nebenstrace
diesen Effekten können Sie das Debug-Out wie folgt erneut verwenden:AUSGABE
Und portabel:
AUSGABE
Grundsätzlich wird die Shell
mv
mit dem Inhalt des Verzeichnisses (wenn es nicht leer ist und keine Dateien / Ordner enthält, deren Namen mit "" beginnen.
) als Argumentliste ausgeführt.mv
wird POSIX angegeben, um sein letztes Argument als Verzeichnis zu interpretieren, wenn es mit mehr als zwei Argumenten aufgerufen wird - auf dieselbe Weiseln
wie (weil es sich in der zugrunde liegenden Funktion tatsächlich um unglaublich ähnliche Tools handelt) .Genug davon
echo
:AUSGABE
Alle Dateien wurden in das letzte Argument verschoben, da es sich um einen Ordner handelt. Was ist nun, wenn es sich nicht um einen Ordner handelt?
AUSGABE
So sollte sich POSIX
mv
in diesem Fall verhalten:Also, wenn
*
erweitert um:zwei Dateien
renamed
zur zweiten nach der zweiten gehörtunlinked
.Eine oder mehrere Dateien, gefolgt von einem Verzeichnis oder einem Link zu einer
noch etwas
quelle
sh
Ding habe ich das Debuggen vergessen, aber in Bezug auf meine ursprüngliche Frage bedeutet es, dass das Problem nicht die Shell istmv
? Das ist böse, es ist einfacher als ich ursprünglich dachte, aber es ist eine echte Falle.*
ist das nicht ein einziges argument? Recht? :)Zuerst wird die Shell
./*
auf alle Dateien im aktuellen Verzeichnis erweitert (außer Dateien, die mit einem Punkt beginnen).mv
schlägt fehlmv
scheitert.quelle
echo ./*
einfach an und sehen Sie, welche Reihenfolge Ihre Shell verwendet (normalerweise alphabetisch).mv
Gibt eine Fehlermeldung zurück, wenn sie nur mit einem Argument aufgerufen wird.missing destination file operand after *filename*
es jetzt , obwohl es gestern nicht geschah.Bei der Eingabe
mv ./*
wird Ihre Shell./*
vor der Ausführung erweitertmv
.Ein paar Dinge zu beachten:
./*
in weniger als 2 Argumente erweitertmv
wird, wird logischerweise ein Fehler erzeugt../*
wird normalerweise in jede Datei (einschließlich Verzeichnis) erweitert, die im aktuellen Verzeichnis vorhanden ist und nicht mit einem Punkt beginnt../*
erweitert wird, indem Sie die Dokumentation Ihrer Shell lesen (man 7 glob
ist ein Einstiegspunkt in das Thema). Unterschiedliche Shells haben unterschiedliche Optionen.quelle
Hier ist eine kürzere Antwort:
Die Shell erweitert den Platzhalter
*
zu einer Liste mit Verzeichnisinhalten. Dann übergibt die Shell diese vollständige Liste an den Befehl. Der Befehl sieht nie*
.Der Befehl
mv file1 file2 ... filen directory
verschiebt file1 ... filen in das Verzeichnis.Beispiel
Hier erstelle ich ein Testverzeichnis mit drei Dateien
Sie können nicht mehrere Dateien in eine einzige Datei verschieben
Fügen wir ein Unterverzeichnis hinzu
Sie können mehrere Dateien in ein Unterverzeichnis verschieben
quelle
mv file1 file2 ... filen directory
ist sehr unwahrscheinlich, dass der Befehl überhaupt etwas damit zu tun hat*
.*
werden würde, esfile dir
sei denn, es gibt ein Gebietsschema, in demd
Folgendes folgtf
.a b c d
das, was nicht istfile ... dir
. Ich habe überhaupt nur kommentiert, weil Sie die Sorte nirgendwo erwähnen und sagen, nur das*
wirdfile ... dir
was nicht passiert.