Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

I copied some file from source folder into destination folder by using bellow command line in terminal.

sudo cp From_SOURCE/* To_DESTINATION/

Now I want to undo this command.

share|improve this question
    
I am not sure I understand. Simply remove the copy? (sudo rm file) –  Jacob Vlijm Aug 10 at 15:21
    
@JacobVlijm it's not undo action it's a separate command. If I didn't copy so I could use your suggested command previously. And I have to more and more time use this command to delete more than 1000 files copied? –  KasiyA Aug 10 at 15:54
    
@KasiyA - a option would be to find all the filenames that were selected from From_SOURCE/*, and remove those from To_DESTINATION/; this could be done with bash - the problems here could include cp command overwrote anything, symlinks were copied, files with spaces in names, etc - so it could have issues and go a bit wacky. A perfect 'undo' option could would have to account for lots of stuff. –  Wilf Aug 10 at 15:59

2 Answers 2

up vote 9 down vote accepted

If I understand well, the following is the case:

  • You copied a (presumably large) number of files on to an existing directory, and you need / want to reverse the action.
  • The targeted directory contains a number of other files, that you need to keep there, which makes it impossible to simply remove all files from the directory

The script below looks in the original (source) directory and lists those files. Then it looks into the directory you copied the files to, and removes only the listed files, as they exist in the source directory.

The try element is added to prevent errors, for example in case you might have removed some files manually already, or if not all files from the source directory were copied to the destination. If you need sudo privileges, simply run the script with "sudo" (see below).

The 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

How to use

  • Paste the script in an empty file, save it as reverse.py,
  • Insert the correct paths for source and target folder,
  • Make it executable for convenience reasons,
  • Run it by the command:

    [sudo] /path/to/reverse.py
    

Warning

First try on a test directory if I understood well what you need to achieve!


If the sourcedirectory is "flat"

In case the source directory has no sub-directories, the script can even be simpler:

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

Note

If the copy action overwrote (replaced) a similarly named file in the destination, the file will be removed, but the original file will (of course) not be brought back by the script. The assumption is that there are no name clashes.

share|improve this answer
    
Thank you. I will try your answer. This is the answer that I expected. –  KasiyA Aug 10 at 18:05
    
It works, thank you. I run it by sudo python3 reverse.py. I accept your answer. –  KasiyA Aug 10 at 19:14
    
Perfect! Thank you for a nice question, which describes a situation we've probably all been in :) –  Jacob Vlijm Aug 10 at 19:16
    
Note: If any file in the source overwrote a file in the destination because it had the same name, then you cannot simply un-do it, and this script will just delete it. The assumption here is that there were no name clashes when you did the initial cp. –  neon_overload Aug 30 at 4:57
    
@neon_overload Correct, edited it in my answer. –  Jacob Vlijm Aug 30 at 5:30

TL;DR:

All files that are present in both src and dest can be removed from dest like this:

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

For a step-by-step, explanation, see below.

Simplifying the problem:

To understand what the command we want to undo actually did, we start by simpifying it:

The command we want to undo is

sudo cp From_SOURCE/* To_DESTINATION/

For understanding how to undo, sudo is not relevant.

I'll use the directory names src for From_SOURCE and dest for To_DESTINATION.

Now, our command is:

cp src/* dest/

If src contains the files f1, f2 and f3, and the directories d1 and d2, the shell expands that command to:

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

Without options like -r, -R or -a, the command cp does not copy directories.
That means, the command will leave them out, showing an error for each of them:

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

That means, we have only copied simple files, and no directories, to dest.

Deciding which files to remove:

Possibly there were files in dest of the same name as files in src. In this case, the files were overwritten (1). It's too late for them, sorry. Get them back from the latest backup.

Regarding the files that are there, we want to remove only files that have been copied over. These files exist in both directories, with the same name, and the same content.

So we look for these files:

First, we cd into src, because it makes the following find commands much simpler, and set a variable to the absolute path of dest:

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

Then, we list all files in src:

$ find . -maxdepth 1 -type f

and, for each file found, use cmp to check whether there is a file with the same content in dest:

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

Removing the files, carefully:

These files are the ones we want to remove. But to be sure, we move them into a different directory first - and take a look at the commands before running them:

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

Looks good! Now we can leave out the echo to run the real mv commands:

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

All the files from dest that were copied from src, and still actually the same in src and dest, are now in /tmp/toDelete/, and can be removed after taking a last look.


Notes:
(1) Check whether cp is an alias to cp -i or so, that would have prevented overwriting files by asking first.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.