Action de la commande Annuler la copie (cp)

14

J'ai copié un fichier du dossier source dans le dossier de destination en utilisant la ligne de commande ci-dessous dans le terminal.

sudo cp From_SOURCE/* To_DESTINATION/

Maintenant, je veux annuler cette commande.

αғsнιη
la source
Je ne suis pas sûr de comprendre. Retirez simplement la copie? (fichier sudo rm)
Jacob Vlijm
@JacobVlijm ce n'est pas une action d'annulation, c'est une commande distincte. Si je n'ai pas copié, je pourrais utiliser votre commande suggérée précédemment. Et je dois de plus en plus utiliser cette commande pour supprimer plus de 1000 fichiers copiés?
αғsнιη
@KasiyA - une option serait de trouver tous les noms de fichiers qui ont été sélectionnés From_SOURCE/*et de les supprimer To_DESTINATION/; cela pourrait être fait avec bash - les problèmes ici pourraient inclure la commande cp écrasé tout, les liens symboliques ont été copiés, les fichiers avec des espaces dans les noms, etc. - donc cela pourrait avoir des problèmes et devenir un peu farfelus. Une option d'annulation parfaite pourrait avoir à prendre en compte beaucoup de choses.
Wilf

Réponses:

13

Si je comprends bien, voici le cas:

  • Vous avez copié un nombre (vraisemblablement important) de fichiers dans un répertoire existant, et vous devez / souhaitez inverser l'action.
  • Le répertoire ciblé contient un certain nombre d' autres fichiers, que vous devez y conserver, ce qui rend impossible de supprimer simplement tous les fichiers du répertoire

Le script ci-dessous regarde dans le répertoire d'origine (source) et répertorie ces fichiers. Il examine ensuite le répertoire dans lequel vous avez copié les fichiers et supprime uniquement les fichiers répertoriés, tels qu'ils existent dans le répertoire source.

L' tryélément est ajouté pour éviter les erreurs, par exemple au cas où vous auriez déjà supprimé certains fichiers manuellement ou si tous les fichiers du répertoire source n'ont pas été copiés vers la destination. Si vous avez besoin des privilèges sudo, exécutez simplement le script avec "sudo" (voir ci-dessous).

Le script

#!/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

Comment utiliser

  • Collez le script dans un fichier vide, enregistrez-le sous reverse.py,
  • Insérez les bons chemins pour les dossiers source et cible,
  • Rendez-le exécutable pour des raisons de commodité,
  • Exécutez-le par la commande:

    [sudo] /path/to/reverse.py
    

avertissement

Essayez d'abord un répertoire de test si j'ai bien compris ce que vous devez réaliser!


Si le répertoire d'origine est "plat"

Dans le cas où le répertoire source n'a pas de sous-répertoires, le script peut même être plus simple:

#!/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

Remarque

Si l'action de copie écrase (remplace) un fichier portant le même nom dans la destination, le fichier sera supprimé, mais le fichier d'origine ne sera (bien sûr) pas restauré par le script. L'hypothèse est qu'il n'y a pas de conflits de noms.

Jacob Vlijm
la source
Cela fonctionne, merci. Je passe devant sudo python3 reverse.py. J'accepte ta réponse.
αғsнιη
Parfait! Merci pour une belle question qui décrit une situation dans laquelle nous avons probablement tous été :)
Jacob Vlijm
Remarque: Si un fichier de la source a remplacé un fichier dans la destination car il portait le même nom, vous ne pouvez pas simplement l'annuler et ce script le supprimera simplement. L'hypothèse ici est qu'il n'y a pas eu de conflits de noms lorsque vous avez fait l'initiale cp.
thomasrutter
@neon_overload Correct, l'a édité dans ma réponse.
Jacob Vlijm
Cela ne fonctionne pas pour cp -r. J'ai changé os.removeavec print, et il génère un tas de fichiers qui n'existent pas. Je suppose qu'il manque les sous-répertoires et ne répertorie que les fichiers à la fin.
Typewar
7

TL; DR:

Tous les fichiers qui sont présents dans les deux srcet destpeuvent être supprimés destcomme ceci:

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

Pour une explication étape par étape, voir ci-dessous.

Simplifier le problème:

Pour comprendre ce que la commande que nous voulons annuler a réellement fait, nous commençons par la simplifier:

La commande que nous voulons annuler est

sudo cp From_SOURCE/* To_DESTINATION/

Pour comprendre comment annuler, sudon'est pas pertinent.

Je vais utiliser les noms de répertoire srcpour From_SOURCEet destpour To_DESTINATION.

Maintenant, notre commande est:

cp src/* dest/

Si srccontient les fichiers f1, f2et f3, et les répertoires d1et d2, le shell étend cette commande à:

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

Sans options telles que -r, -Rou -a, la commande cpne copie pas les répertoires.
Cela signifie que la commande les laissera de côté, affichant une erreur pour chacun d'eux:

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

Cela signifie que nous n'avons copié que des fichiers simples et aucun répertoire dest.

Décider quels fichiers supprimer:

Il y avait peut-être des fichiers destdu même nom que des fichiers dans src. Dans ce cas, les fichiers ont été écrasés (1). Il est trop tard pour eux, désolé. Récupérez-les à partir de la dernière sauvegarde.

En ce qui concerne les fichiers qui s'y trouvent, nous voulons supprimer uniquement les fichiers qui ont été copiés. Ces fichiers existent dans les deux répertoires, avec le même nom et le même contenu.

Nous recherchons donc ces fichiers:

Tout d'abord, nous allons cddans src, car cela rend les findcommandes suivantes beaucoup plus simples, et définissons une variable sur le chemin absolu de dest:

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

Ensuite, nous listons tous les fichiers dans src:

$ find . -maxdepth 1 -type f

et, pour chaque fichier trouvé, utilisez cmppour vérifier s'il existe un fichier avec le même contenu dans dest:

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

Suppression des fichiers, soigneusement:

Ces fichiers sont ceux que nous voulons supprimer. Mais pour être sûr, nous les déplaçons d'abord dans un répertoire différent - et examinons les commandes avant de les exécuter:

$ 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/`

Cela semble bon! Maintenant, nous pouvons laisser de côté echopour exécuter les vraies mvcommandes:

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

Tous les fichiers destqui ont été copiés srcet qui sont toujours les mêmes dans srcet dest, sont maintenant dans /tmp/toDelete/et peuvent être supprimés après un dernier examen.


Remarques:
(1) Vérifiez s'il cps'agit d'un alias cp -iou qui aurait empêché l'écrasement des fichiers en demandant d'abord.

Volker Siegel
la source
5

C'est vieux, mais je voulais juste poster une réponse bash pure:

Accédez d'abord au répertoire dans lequel vous avez copié les fichiers.

cd dest

Ensuite, lsle répertoire source et dirigez la sortie versrm

ls source | xargs rm

Michael Goldstein
la source
1
l'analyse lsest généralement une mauvaise idée. mywiki.wooledge.org/ParsingLs Je ne revoterai pas votre message, mais il faut le noter.
Sergiy Kolodyazhnyy