Kopiervorgang (cp) rückgängig machen

14

Ich habe eine Datei vom Quellordner in den Zielordner kopiert, indem ich die folgende Befehlszeile im Terminal verwendet habe.

sudo cp From_SOURCE/* To_DESTINATION/

Jetzt möchte ich diesen Befehl rückgängig machen.

αғsнιη
quelle
Ich bin mir nicht sicher, ob ich das verstehe. Einfach die Kopie entfernen? (sudo rm file)
Jacob Vlijm
@JacobVlijm Es ist keine Aktion rückgängig zu machen, sondern ein separater Befehl. Wenn ich nicht kopieren würde, könnte ich Ihren vorgeschlagenen Befehl vorher verwenden. Und ich muss immer mehr Zeit mit diesem Befehl mehr als 1000 kopierte Dateien löschen?
αғsнιη
@KasiyA - Eine Option wäre, alle Dateinamen zu finden, aus denen ausgewählt wurde From_SOURCE/*, und diese zu entfernen To_DESTINATION/. Dies könnte mit bash geschehen - die Probleme könnten darin bestehen, dass der Befehl cp alles überschreibt, Symlinks kopiert werden, Dateien mit Leerzeichen in Namen usw. -, also könnte es Probleme geben und etwas verrückt werden. Eine perfekte "Rückgängig" -Option könnte eine Menge Dinge berücksichtigen müssen.
Wilf

Antworten:

13

Wenn ich es richtig verstehe, ist Folgendes der Fall:

  • Sie haben eine (vermutlich große) Anzahl von Dateien in ein vorhandenes Verzeichnis kopiert und möchten die Aktion rückgängig machen.
  • Das Zielverzeichnis enthält eine Reihe weiterer Dateien, die Sie dort aufbewahren müssen, sodass es nicht möglich ist, alle Dateien einfach aus dem Verzeichnis zu entfernen

Das folgende Skript durchsucht das ursprüngliche (Quell-) Verzeichnis und listet diese Dateien auf. Dann wird in das Verzeichnis geschaut, in das Sie die Dateien kopiert haben, und es werden nur die aufgelisteten Dateien entfernt, die im Quellverzeichnis vorhanden sind.

Das tryElement wird hinzugefügt, um Fehler zu vermeiden, zum Beispiel, wenn Sie einige Dateien bereits manuell entfernt haben oder wenn nicht alle Dateien aus dem Quellverzeichnis in das Ziel kopiert wurden. Wenn Sie sudo-Berechtigungen benötigen, führen Sie das Skript einfach mit "sudo" aus (siehe unten).

Das Drehbuch

#!/usr/bin/env python

import os

source_dir = "/path/to/source" # the folder you copied the files from
target_folder = "/path/to/destination" # the folder you copied the files to

for root, dirs, files in os.walk(source_dir):
    for name in files:
        try:
            os.remove(target_folder+"/"+name)
        except FileNotFoundError:
            pass

Wie benutzt man

  • Füge das Skript in eine leere Datei ein, speichere es als reverse.py,
  • Geben Sie die richtigen Pfade für Quell- und Zielordner ein.
  • Machen Sie es aus praktischen Gründen ausführbar,
  • Führen Sie es mit folgendem Befehl aus:

    [sudo] /path/to/reverse.py
    

Warnung

Probieren Sie zuerst ein Testverzeichnis aus, wenn ich verstanden habe, was Sie erreichen müssen!


Wenn das Quellverzeichnis "flach" ist

Falls das Quellverzeichnis keine Unterverzeichnisse enthält, kann das Skript noch einfacher sein:

#!/usr/bin/env python

import os

source_dir = "/path/to/source" # the folder you copied the files from
target_folder = "/path/to/destination" # the folder you copied the files to

for file in os.listdir(source_dir):
    try:
        os.remove(target_folder+"/"+file)
    except FileNotFoundError:
        pass

Hinweis

Wenn die Kopieraktion eine Datei mit ähnlichem Namen im Ziel überschreibt (ersetzt), wird die Datei entfernt, aber die ursprüngliche Datei wird (natürlich) nicht vom Skript zurückgebracht. Die Annahme ist, dass es keine Namenskonflikte gibt.

Jacob Vlijm
quelle
Es funktioniert, danke. Ich führe es durch sudo python3 reverse.py. Ich akzeptiere deine Antwort.
αғsнιη
Perfekt! Vielen Dank für eine nette Frage, die eine Situation beschreibt, in der wir wahrscheinlich alle waren :)
Jacob Vlijm
Hinweis: Wenn eine Datei in der Quelle eine Datei im Ziel überschrieb, weil sie den gleichen Namen hatte, können Sie dies nicht einfach rückgängig machen, und dieses Skript löscht sie einfach. Die Annahme hier ist, dass es keine Namenskonflikte gab, als Sie die Initiale machten cp.
Thomasrutter
@neon_overload Richtig, habe es in meiner Antwort bearbeitet.
Jacob Vlijm
Dies funktioniert nicht für cp -r. Ich änderte os.removemit print, und es wird eine Reihe von Dateien ausgibt, die nicht existieren. Ich gehe davon aus, dass die Unterverzeichnisse fehlen und nur die Dateien am Ende aufgelistet sind.
Typewar
7

TL; DR:

Alle Dateien, die in beiden vorhanden sind srcund destwie folgt entfernt werden destkönnen:

find . -maxdepth 1 -type f -exec cmp -s '{}' "$destdir/{}" \; -exec mv -n "$destdir/{}" "$toDelete"/ \;

Eine schrittweise Erklärung finden Sie weiter unten.

Das Problem vereinfachen:

Um zu verstehen, was der Befehl, den wir rückgängig machen möchten, tatsächlich gemacht hat, vereinfachen wir ihn zunächst:

Der Befehl, den wir rückgängig machen möchten, lautet

sudo cp From_SOURCE/* To_DESTINATION/

Für das Verständnis, wie man rückgängig macht, sudoist das nicht relevant.

Ich werde die Verzeichnisnamen srcfür From_SOURCEund destfür verwenden To_DESTINATION.

Unser Befehl lautet nun:

cp src/* dest/

Wenn srcenthält die Dateien f1, f2und f3, und die Verzeichnisse d1und d2erweitert die Shell diesen Befehl zu:

cp src/f1 src/f2 src/f3 src/d1 src/d2 dest/

Ohne Optionen mögen -r, -Roder -ader Befehl cpkopiert keine Verzeichnisse.
Das heißt, der Befehl lässt sie weg und zeigt für jede von ihnen einen Fehler an:

$ cp src/f1 src/f2 src/f3 src/d1 src/d2 dest/
cp: omitting directory 'src/d1'
cp: omitting directory 'src/d2'

Das heißt, wir haben nur einfache Dateien und keine Verzeichnisse nach kopiert dest.

Entscheiden, welche Dateien entfernt werden sollen:

Möglicherweise gab es Dateien destmit demselben Namen wie Dateien in src. In diesem Fall wurden die Dateien überschrieben (1). Es ist zu spät für sie, sorry. Holen Sie sie von der neuesten Sicherung zurück.

In Bezug auf die Dateien, die sich dort befinden, möchten wir nur Dateien entfernen, die kopiert wurden. Diese Dateien existieren in beiden Verzeichnissen mit demselben Namen und demselben Inhalt.

Also suchen wir nach diesen Dateien:

Erstens haben wir cdin src, denn es macht die folgenden findBefehle wesentlich einfacher, und eine Variable auf den absoluten Pfad von dest gesetzt:

$ cd src
$ destdir="$(readlink -f dest)"

Dann listen wir alle Dateien in src auf:

$ find . -maxdepth 1 -type f

cmpÜberprüfen Sie für jede gefundene Datei, ob sich in dest eine Datei mit demselben Inhalt befindet:

$ find . -maxdepth 1 -type f -exec cmp -s '{}' "$destdir/{}" \; -print

Entfernen Sie die Dateien sorgfältig:

Diese Dateien möchten wir entfernen. Aber um sicherzugehen, verschieben wir sie zuerst in ein anderes Verzeichnis - und werfen einen Blick auf die Befehle, bevor wir sie ausführen:

$ toDelete=/tmp/toDelete ; mkdir -p "$toDelete"
$ find . -maxdepth 1 -type f -exec cmp -s '{}' "$destdir/{}" \; -exec echo mv -n "$destdir/{}" "$toDelete"/ \;
mv -n /path/to/dest/./f1 /tmp/toDelete/`
mv -n /path/to/dest/./f2 /tmp/toDelete/`
mv -n /path/to/dest/./f3 /tmp/toDelete/`

Sieht gut aus! Jetzt können wir das weglassen, echoum die echten mvBefehle auszuführen:

find . -maxdepth 1 -type f -exec cmp -s '{}' "$destdir/{}" \; -exec mv -n "$destdir/{}" "$toDelete"/ \;

Alle Dateien, aus destdenen kopiert srcwurden und die immer noch in srcund sind dest, befinden sich jetzt in /tmp/toDelete/und können nach einem letzten Blick entfernt werden.


Anmerkungen:
(1) Überprüfen Sie, ob cpes sich um einen Alias ​​handelt cp -i, der das Überschreiben von Dateien verhindert hätte, indem Sie zuerst danach fragen.

Volker Siegel
quelle
5

Dies ist alt, aber ich wollte nur eine reine Bash-Antwort posten:

Wechseln Sie zunächst in das Verzeichnis, in das Sie die Dateien kopiert haben.

cd dest

Dann lsdas Quellverzeichnis und leiten Sie die Ausgabe inrm

ls source | xargs rm

Michael Goldstein
quelle
1
Parsen lsist normalerweise eine schlechte Idee. mywiki.wooledge.org/ParsingLs Ich werde Ihren Beitrag nicht ablehnen, aber es muss beachtet werden.
Sergiy Kolodyazhnyy