Wie kann man verhindern, dass `mv` eine Sammlung von Dateien in eine einzige reguläre verschiebt?

17

Ich habe gerade einen kleinen Teil meiner Audiosammlung durch einen blöden Fehler verloren. :-(
GLADLY Ich hatte ein ziemlich aktuelles Backup, aber es war immer noch ärgerlich. Abgesehen von deinem, war der andere Schuldige, der das Unheil angerichtet hat, der folgende Beweis mv:

Die Audiodateien hatten ein bestimmtes Schema:

ARTIST - Some Title YY.mp3

Wo YYist die zweistellige Jahresangabe?

mkdir 90<invisible control character>

(Bis zu diesem Moment wusste ich nicht, dass ich tatsächlich ein Drittel überschüssigen Zeichens eingegeben hatte, das unsichtbar war ...!)
Anstatt alles in einem Verzeichnis zu haben, wollte ich alle Musik der 90er Jahre in einem Verzeichnis haben. Also schrieb ich:

find . -name '* 9?.mp3' -exec mv {} 90 \;

Nicht so schwer, die Idee zu bekommen, was eh passiert ist? : ->
Das (katastrophale) Ergebnis war ein jungfräuliches leeres Verzeichnis mit dem Namen '90 something '(wobei etwas das "unsichtbare" Steuerzeichen ist) und eine einzelne Datei mit dem Namen' 90 ', die n- mal überschrieben wurde.

ALLE DATEIEN WURDEN GEGANGEN. : - (((offensichtlich)

Ich wünschte mv, ich hätte rechtzeitig überprüft, ob die Signatur der Zieldatei (bitte beachten Sie * NIX: Everything Is A File ) mit einem d------(z drwxr-xr-x. B. ) beginnt . Und natürlich, ob das Ziel überhaupt existiert . Es ist eine Variante des oben genannten Szenarios, wenn man einfach vergessen zu mkdirerstem Verzeichnis. (aber natürlich hast du angenommen, dass es da ist ...)

Sogar unser Hass-Betriebssystem, das mit der Hauptstadt W beginnt, tut dies. Sie werden sogar aufgefordert , den Zieltyp (Datei? Verzeichnis?) Anzugeben, wenn Sie danach fragen.

Daher frage ich mich, ob wir * NIXer uns noch ein " mvScriptlet" schreiben müssen , um diese Art von unerwünschten Überraschungen zu vermeiden.

Syntax-Fehler
quelle
2
Nicht alle Dateien waren weg. Es sollte mindestens einer .mp3mit dem Namen vorhanden sein 90, es könnte einer gewesen sein, für den Sie kein Backup hatten.
Anthon
2
Heh, du hast einen zynischen Sinn für Humor, du verrückt dich! :-P Nun, das war die Datei namens "eine einzige Datei" in Fettdruck in meinem OP. :)
Syntaxfehler
2
mvTechnisch gesehen ist dies nicht das Problem, da nicht bekannt ist, dass Sie eine Reihe von Dateien verschieben. Sie werden mveinmal für jede Datei ausgeführt. So find -exec ;funktioniert es. Wenn Sie verwendet hätten find -exec +(wie in einigen Kommentaren) mv würde hätte es geschrien, sobald es mehr als ein Argument bekommen hätte.
Etan Reisner
Obwohl das Ausführen mvfür jede einzelne Datei auf den ersten Blick weniger durchdacht erscheint, wird es (wie ich bereits sagte) die einzig vernünftige Lösung sein, wenn die Quelldateien auf verschiedene Unterverzeichnisse verteilt sind. Dass sich in meinem Testfall alle Quelldateien in einem Verzeichnis befanden, bedeutet nicht, dass es sich um meinen eigentlichen Testfall handelt. Es ist in der Tat nur eine Vereinfachung, da ich das später leicht selbst ausführen kann. Darüber hinaus ist das Lesen von Fragen aufgrund der kürzeren Länge weniger zeitaufwändig. :)
Syntaxfehler
Warum sollten Sie damit rechnen? mv , dass das Ziel existiert? mv oldfile newfileist der Weg, eine Datei umzubenennen, und es ist albern zu erwarten newfile, dass sie bereits existiert und ein Verzeichnis ist.
Barmar

Antworten:

37

Sie können ein /an das Ziel anhängen , wenn Sie Dateien in ein Verzeichnis verschieben möchten. Falls das Verzeichnis nicht existiert, erhalten Sie eine Fehlermeldung:

mv somefile somedir/
mv: cannot move ‘somefile’ to ‘somedir/’: Not a directory

Falls das Verzeichnis existiert, verschiebt es die Datei in dieses Verzeichnis.

Marco
quelle
4
Ich danke dir sehr! Das sollte dann mein zukünftiger Lebensretter sein. Ich schulde dir etwas. (Nur als Hinweis, ein Freund von mir hatte vor einigen Jahren den gleichen Fehler
begangen
1
Wenn Sie bestimmte Shells verwenden, haben Sie auch die Tabulator-Option, um Dateinamen automatisch für Sie zu vervollständigen. Wenn ich mich nicht genau an den Verzeichnisnamen erinnern kann und keine Unordnung wie in der letzten Zeit haben möchte, geben Sie einfach ein oder zwei Zeichen aus dem Verzeichnisnamen und der Tabulatortaste ein . Dann können Sie sicher sein, dass es existiert, weil Auto-Vervollständigen Sie es dort ....
Andyz Smith
@AndyzSmith Nun, das ist genau das Richtige. Sie können es als meine Gewohnheit bezeichnen, TAB immer nur für komplizierte Verzeichnisse oder Pfade zu verwenden, aber nicht für Verzeichnisse mit zwei Buchstaben von jetzt an.
Syntaxfehler
20

Das GNU-Coreutils hat mvbereits eine Option, die angibt, dass Sie in ein Verzeichnis verschieben möchten: -t/ --target-directory. Wenn das Argument für diese Option nicht vorhanden ist, mvwerden Sie sich beschweren, anstatt alle Ihre Dateien in den gleichen Dateinamen zu verschieben.

Ich hätte deinen Urheber wie folgt geschrieben:

find . -name '* 9?.mp3' -exec mv -t 90 {} +

Beachten Sie, dass +stattdessen \;so viele Dateinamen wie möglich zusammengefasst werden, was zu einer schnelleren Ausführung führt.

Anthon
quelle
Vielen Dank. (
Ich hoffe,
2
@Syntax-Fehler. Es ist ein GNUism. POSIXly:find . -name '* 9?.mp3' -exec sh -c 'exec mv "$@" 90/' sh {} +
Stéphane Chazelas
Vielen Dank für diesen SNEAKY-Einzeiler! Stellen Sie sich vor, es wären +5, die ich Ihnen gegeben habe. :) Macht viele Versuche unnötig. - Und Sie wissen zu gut, warum ich diese Bemerkung gemacht habe. Ich muss mich nur auf einer Maschine befinden, die direkt auf POSIX basiert (was nicht allzu selten vorkommt), und genau dort werde ich das nächste Problem haben. :)
Syntaxfehler
1
@syntaxerror Wenn diese Antwort Ihr Problem löst, nehmen Sie sich bitte eine Minute Zeit und klicken Sie auf das Häkchen unter der Anzahl der abgegebenen Stimmen links. Dies bedeutet für alle, dass Ihr Problem behoben wurde, und ist die Art und Weise, wie auf der Website der Dank ausgesprochen wird. Ich habe gesehen, dass nur einige Ihrer anderen beantworteten Fragen Antworten akzeptiert haben. Vielleicht möchten Sie auch diese prüfen.
Anthon
Nein, es ist einfach ein Zweck. Ich würde oft mehrere Wochen oder manchmal 2 Monate warten, bis ich eine Antwort akzeptiere. Der Grund ist, dass einige sehr sachkundige Personen einen SEHR vollen Zeitplan haben und möglicherweise erst nach ein paar Wochen Zeit finden, ihre (normalerweise beste) Antwort zu geben. Deshalb finde ich es immer nur respektvoll, darauf zu warten, dass sie vorbeischauen. Nun, und wenn sie es wirklich nicht tun, zögere ich nicht, das Häkchen zu setzen. Außerdem verstehe ich nicht, warum manche Leute es immer so eilig haben, was SE + seine Aromen angeht. Einfach, Jungs. Spring nicht mit der Waffe. :) Das ist nicht dein Chef, der auf dich drückt.
Syntaxfehler
10

Wenn Sie in Zukunft generell ein versehentliches Überschreiben vermeiden möchten, gibt es die -iOption für mv. Ich persönlich kann mir keine Nachteile vorstellen, wenn Sie

alias mv='mv -i'

Wenn Sie dann etwas überschreiben müssen, übergeben Sie einfach die -f Option.

Aliase werden nur wirksam, wenn Sie den Befehl direkt in eine interaktive Shell eingeben, nicht in Fällen wie dem Aufruf durch find. Du hättest laufen können

find . -name '* 9?.mp3' -exec mv -i {} 90 \;

und dann wären Sie gefragt mvworden, ob Sie versucht hätten, eine vorhandene Datei zu überschreiben.

ayekat
quelle
4
Oder - wie Sie wahrscheinlich nicht wussten - geben Sie statt ´ \ mv` ein mv. Dieser weniger bekannte „Trick“ bewirkt , dass der Befehl mit dem umgekehrten Schrägstrich vorangestellt zu ignorieren alle Alias - Definitionen.
Syntaxfehler
Natürlich müssen Sie, wenn Sie wirklich darüber sprechen find ... -exec mv ..., ein ~/bin/mvVerzeichnis erstellen (oder ein anderes geeignetes Verzeichnis) und es erstellen lassen /bin/mv -i "$@"- weil Sie find ... -execsich keine Aliase ansehen.
G-Man sagt, dass Monica
In diesem Fall würde ich bevorzugen env mv. Weniger tippen. :) Da für mein lokales Tastaturlayout das Drücken der UMSCHALTTASTE für einen Schrägstrich erforderlich ist, würde ich (falls zutreffend) immer "Schrägstrichlose" Versionen bevorzugen.
Syntaxfehler
1
@syntaxerror: Übrigens, wenn Sie auf einen Kommentar (in einem neuen Kommentar) antworten, ist es üblich, den Namen des Autors vor dem "@" zu erwähnen, wie in "@ G-Man". Auf diese Weise werde ich benachrichtigt. (Ich konnte auf Ihren letzten Kommentar zeitnah reagieren, da ich durch den Kommentar von Jenny D benachrichtigt wurde.) Sie können einen vollständigen Namen (ohne Leerzeichen) verwenden, z. B. "@ StéphaneChazelas". Der Autor eines Beitrags wird automatisch über Kommentare zu diesem Beitrag benachrichtigt. Siehe den Abschnitt Antworten in Kommentaren auf dieser Hilfeseite .
G-Man sagt, dass Monica
1
Es tut mir leid, ich war einen Tag lang ohne Internet. @ G-Man Ich bin damit einverstanden, dass eine persönliche Version von mvan einem Ort am Anfang $PATHeine sauberere Lösung wäre. Auf der anderen Seite passiere ich vor allem mvsorglos in der interaktiven Shell (weil es schnell geht). In dem Moment, in dem ich etwas Komplexeres komponiere, wie findeine forSchleife oder sogar ein Shell-Skript, tendiere ich dazu, ein paar Probeläufe (mit echo) durchzuführen, um sicherzustellen, dass ich nichts kaputt mache. In solchen Fällen brauche ich kein Händchen mv, weil ich mir schon Gedanken mache.
Ayekat
7

Zusätzlich zu den hervorragenden Antworten oben möchte ich klären, warum Sie nicht die Frage haben, ob Sie die Dateien verschieben sollen oder nicht.

Wenn Sie eine Datei an einen neuen Namen verschieben und dieser Name kein Verzeichnis ist,mv wird Ihre Datei in den neuen Namen umbenannt.

Das Problem hierbei ist , dass Sie wurden unter Verwendung findauszuführen mveinmal pro Datei , nicht einmal für alle Dateien .

Wenn Sie es stattdessen getan hätten mv *90.mp3 90, dann mv wäre die Fehlermeldung "Die Zieldatei ist kein Verzeichnis" fehlgeschlagen.

Ein weiterer Ratschlag ist die Verwendung der Tabulatorvervollständigung beim Eingeben des Zielpfads. Durch Hinzufügen /zum Zielnamen wird angezeigt, ob das Ziel ein Verzeichnis ist . Sie können auch mv -imit gefragt werden, ob Sie eine vorhandene Datei überschreiben möchten.

Jenny D
quelle
Wenn Sie dies getan hätten mv *90.mp3 90, wäre mv mit der Fehlermeldung "Die Zieldatei ist kein Verzeichnis" fehlgeschlagen. Hah ja warum so kompliziert eh Ich benutze deine Leitung und ich werde glücklich sein. Nur in diesem trivialen Fall. :) Weil das die normale Art ist, wie ich meine Fragen stelle: Ich hätte sie der Einfachheit halber eingegrenzt. Bisher hat niemand etwas dagegen einzuwenden, finddass die Dateien der 90er Jahre genauso gut in verschiedenen Unterverzeichnissen verstreut sind, die ich ebenfalls "fangen" möchte. Wenn und nur wenn sie sich immer in einem Quellverzeichnis befinden, ist Ihre mvZeile anwendbar.
Syntaxfehler
@syntaxerror Sehr wahr - ich meinte dies als Beispiel für das Verhalten mvund nicht als Kritik an der Auswahl der Tools.
Jenny D
1
Sie könnten wahrscheinlich etwas Kombinierendes bauen findund mvz. B. find /music -type d -exec mv {}/*90.mp3 targetdir\;- aber jetzt habe ich das Gefühl, dass ich es zu kompliziert mache und einfach -ioder -teffizienter benutze
Jenny D
1
@Jenny: Wenn Ihr find . -type d -exec mv {}/*9?.mp3 target \;Beispiel funktioniert, besteht immer noch das Risiko, dass der mvBefehl mv file targetfür jedes Verzeichnis, das nur eine *9?.mp3Datei enthält, so aussieht . Alle diese Dateien (mit Ausnahme der letzten) würden verloren gehen.
G-Man sagt, dass Monica
4
@syntaxerror: Ich begrüße Ihre Bemühungen, den wesentlichen Teil Ihres Problems aufzudecken, und nicht das gesamte 42.000-Zeilen-Skript, in dem es vorkommt. Aber selbst wenn Sie mit allen *.mp3Dateien in einem Verzeichnisbaum etwas anfangen möchten , können Sie shopt -s globstarIhren Befehl ausführen **/*.mp3- der **Wille verhält sich wie ein find.
G-Man sagt, dass Monica
1

Als alternative Allzweckstrategie möchte ich vorschlagen, diese Art von Operation in ein temporäres Skript umzuwandeln. Ich ziehe es vor, die Ergebnisse zu betrachten findund sie mvvon Hand in einen Befehl umzuwandeln, um sicherzustellen, dass ich verstehe, was ich tue, bevor ich sie ausführe. z.B.

find . -name '* 9?.mp3' > tmp
vim tmp

Jetzt kann ich eine Liste der Dateinamen durchsehen und den Dateiinhalt als Shell-Befehl neu schreiben.

  • Setzen Sie den Dateiinhalt in eine Zeile: ggVGJ
  • Voranstellen: Imv [esc]
  • Anhängen: Asomedir/ [esc]
  • Speicher die Datei. Lies es nochmals. Hol erstmal Luft.
  • Führen Sie source tmpin der Befehlszeile aus.

Es ist eine konservative Strategie, aber ich habe von vertippte zu oft gebissen worden -execodersed Befehlen oder falsch verstehen Shell - Erweiterungen, und ich ziehe einen langsamen konsequenten Ansatz.

Mit anderen Worten: Ich bin zu feige, um es zu gebrauchen -exec.

Tom Rees
quelle
1
Sie haben den :%s/.*/"&"/Schritt weggelassen, weil Sie in diesem Fall wissen, dass jeder Dateiname mindestens ein Leerzeichen enthält.
G-Man sagt, dass Monica
1
Dies wird Sie beißen, wenn die Dateinamen Leerzeichen oder andere Sonderzeichen enthalten. Sie müssen sie richtig zitieren. Das Überprüfen einer Befehlsliste ist nicht besonders fehleranfällig. Es gibt weitaus bessere Möglichkeiten, Befehle zu überprüfen, bevor Sie sie ausführen, z. B. Ausführen echo mvstatt mvund anschließendes Entfernen der Option , echowenn Sie zufrieden sind.
Gilles 'SO- hör auf böse zu sein'
Das Erkennen eines Fehlers wie Dateinamen mit Leerzeichen ist genau das, was diese Technik hilft :-)
Tom Rees
0

Andere Option:

-n, --no-clobber überschreibt keine vorhandene Datei

Es ist dasselbe wie -i, aber es wird nicht gefragt, es wird scheitern.

Jorge Nerín
quelle