Annulla l'azione di comando copia (cp)


14

Ho copiato alcuni file dalla cartella di origine nella cartella di destinazione utilizzando la seguente riga di comando nel terminale.

sudo cp From_SOURCE/* To_DESTINATION/

Ora voglio annullare questo comando.


Non sono sicuro di aver capito. Rimuovere semplicemente la copia? (file sudo rm)
Jacob Vlijm

@JacobVlijm non è un'azione di annullamento, ma un comando separato. Se non lo avessi copiato, avrei potuto usare il comando suggerito in precedenza. E devo usare sempre più tempo questo comando per cancellare più di 1000 file copiati?
αғsнιη,

@KasiyA - un'opzione sarebbe quella di trovare tutti i nomi dei file che sono stati selezionati From_SOURCE/*e rimuoverli da To_DESTINATION/; questo potrebbe essere fatto con bash - i problemi qui potrebbero includere il comando cp sovrascritto qualsiasi cosa, i collegamenti simbolici sono stati copiati, i file con spazi nei nomi, ecc. - Quindi potrebbero avere problemi e andare un po 'stravaganti. Un'opzione di "annullamento" perfetta potrebbe dover tenere conto di molte cose.
Wilf

Risposte:


13

Se ho capito bene, è il caso seguente:

  • Hai copiato un numero (presumibilmente grande) di file in una directory esistente e devi / vuoi invertire l'azione.
  • La directory di destinazione contiene una serie di altri file, che è necessario mantenere lì, il che rende impossibile rimuovere semplicemente tutti i file dalla directory

Lo script seguente cerca nella directory (sorgente) originale ed elenca quei file. Quindi esamina la directory in cui hai copiato i file e rimuove solo i file elencati, come esistono nella directory di origine.

L' tryelemento viene aggiunto per prevenire errori, ad esempio nel caso in cui sia possibile che alcuni file siano già stati rimossi manualmente o che non tutti i file dalla directory di origine siano stati copiati nella destinazione. Se hai bisogno dei privilegi di sudo, esegui semplicemente lo script con "sudo" (vedi sotto).

Il copione

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

Come usare

  • Incolla lo script in un file vuoto, salvalo come reverse.py,
  • Inserisci i percorsi corretti per la cartella di origine e di destinazione,
  • Renderlo eseguibile per motivi di convenienza,
  • Eseguilo con il comando:

    [sudo] /path/to/reverse.py
    

avvertimento

Prima prova su una directory di test se ho capito bene cosa devi ottenere!


Se la directory di origine è "piatta"

Nel caso in cui la directory di origine non abbia sottodirectory, lo script può anche essere più semplice:

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

Nota

Se l'azione di copia ha sovrascritto (sostituito) un file con un nome simile nella destinazione, il file verrà rimosso, ma il file originale (ovviamente) non verrà riportato dallo script. Il presupposto è che non ci sono scontri di nomi.


Funziona, grazie. Lo corro sudo python3 reverse.py. Accetto la tua risposta
αғsнιη

Perfetto! Grazie per una bella domanda, che descrive una situazione in cui probabilmente siamo stati tutti :)
Jacob Vlijm

Nota: se qualsiasi file nell'origine sovrascrive un file nella destinazione perché aveva lo stesso nome, non è possibile semplicemente annullarlo e questo script lo eliminerà. Il presupposto qui è che non ci sono stati scontri di nomi quando hai fatto l'iniziale cp.
thomasrutter

@neon_overload Corretto, modificato nella mia risposta.
Jacob Vlijm,

Questo non funziona per cp -r . Ho cambiato os.removecon print, e sta producendo un mucchio di file che non esiste. Suppongo che manchi le sottodirectory e che elenchi solo i file alla fine.
Typewar,

7

TL; DR:

Tutti i file presenti in entrambi srce che destpossono essere rimossi da destquesto:

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

Per una spiegazione dettagliata, vedere di seguito.

Semplificare il problema:

Per capire cosa ha effettivamente fatto il comando che vogliamo annullare, iniziamo semplificandolo:

Il comando che vogliamo annullare è

sudo cp From_SOURCE/* To_DESTINATION/

Per capire come annullare, sudonon è rilevante.

Userò i nomi delle directory srcper From_SOURCEe destper To_DESTINATION.

Ora, il nostro comando è:

cp src/* dest/

Se srccontiene i file f1, f2ef3 , e le directory d1e d2, la shell espande quel comando a:

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

Senza opzioni come -r, -Ro -a, il comandocp non copia le directory.
Ciò significa che il comando li lascerà fuori, mostrando un errore per ciascuno di essi:

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

Ciò significa che abbiamo copiato solo file semplici e nessuna directory dest.

Decidere quali file rimuovere:

Forse c'erano dei file dest lo stesso nome dei file in src. In questo caso, i file sono stati sovrascritti (1). È troppo tardi per loro, scusa. Riportali dall'ultimo backup.

Per quanto riguarda i file presenti, vogliamo rimuovere solo i file che sono stati copiati. Questi file esistono in entrambe le directory, con lo stesso nome e lo stesso contenuto.

Quindi cerchiamo questi file:

In primo luogo, cdin src, perché rende i seguenti findcomandi molto più semplici, e impostare una variabile per il percorso assoluto della dest:

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

Quindi, elenchiamo tutti i file in src:

$ find . -maxdepth 1 -type f

e, per ogni file trovato, utilizzare cmpper verificare se esiste un file con lo stesso contenuto in dest:

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

Rimozione dei file, con attenzione:

Questi file sono quelli che vogliamo rimuovere. Ma per sicurezza, li spostiamo prima in una directory diversa - e diamo un'occhiata ai comandi prima di eseguirli:

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

Sembra buono! Ora possiamo tralasciare echodi eseguire i mvcomandi reali :

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

Tutti i file da destcui sono stati copiati src, e in realtà sono sempre gli stessi in srce dest, sono ora in /tmp/toDelete/e possono essere rimossi dopo aver dato un ultimo sguardo.


Note:
(1) Controlla se cpè un alias cp -io giù di lì, che avrebbe impedito la sovrascrittura dei file chiedendo prima.


5

Questo è vecchio, ma volevo solo pubblicare una risposta bash pura:

Innanzitutto, passa alla directory in cui hai copiato i file.

cd dest

Quindi, lsla directory di origine e reindirizza l'outputrm

ls source | xargs rm


1
l'analisi lsè in genere una cattiva idea. mywiki.wooledge.org/ParsingLs Non voglio sottovalutare il tuo post, ma va notato.
Sergiy Kolodyazhnyy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.