Desfazer ação do comando copy (cp)


14

Copiei algum arquivo da pasta de origem para a pasta de destino usando a linha de comando abaixo no terminal.

sudo cp From_SOURCE/* To_DESTINATION/

Agora eu quero desfazer este comando.


Não sei se entendi. Basta remover a cópia? (sudo arquivo rm)
— Jacob Vlijm

@JacobVlijm não é ação de desfazer, é um comando separado. Se eu não copiasse, poderia usar seu comando sugerido anteriormente. E eu tenho que usar cada vez mais este comando para excluir mais de 1000 arquivos copiados?
— αғsнιη

@KasiyA - uma opção seria encontrar todos os nomes de arquivos selecionados From_SOURCE/*e removê-los To_DESTINATION/; isso pode ser feito com o bash - os problemas aqui podem incluir o comando cp, substituindo qualquer coisa, links simbólicos foram copiados, arquivos com espaços em nomes etc. - para que ele possa ter problemas e ficar um pouco maluco. Uma opção perfeita de "desfazer" poderia ser responsável por muitas coisas.
— Wilf

Respostas:


13

Se bem entendi, é o seguinte:

  • Você copiou um número (presumivelmente grande) de arquivos para um diretório existente e precisa / deseja reverter a ação.
  • O diretório de destino contém vários outros arquivos que você precisa manter lá, o que torna impossível simplesmente remover todos os arquivos do diretório

O script abaixo procura no diretório original (fonte) e lista esses arquivos. Em seguida, ele analisa o diretório para o qual você copiou os arquivos e remove apenas os arquivos listados, pois existem no diretório de origem.

O tryelemento é adicionado para evitar erros, por exemplo, caso você já tenha removido alguns arquivos manualmente ou se nem todos os arquivos do diretório de origem foram copiados para o destino. Se você precisar de privilégios de sudo, basta executar o script com "sudo" (veja abaixo).

O 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

Como usar

  • Cole o script em um arquivo vazio, salve-o como reverse.py,
  • Insira os caminhos corretos para a pasta de origem e destino,
  • Torne-o executável por razões de conveniência,
  • Execute-o pelo comando:

    [sudo] /path/to/reverse.py
    

Atenção

Primeiro tente um diretório de teste se eu entendi bem o que você precisa alcançar!


Se o diretório de origem for "plano"

Caso o diretório de origem não possua subdiretórios, o script pode ser ainda mais simples:

#!/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 a ação de copiar overwrote (substituído) um arquivo de nome semelhante no destino, o arquivo será removido, mas o arquivo original (é claro) não ser trazido de volta pelo script. A suposição é que não há conflitos de nome.


Funciona, obrigado. Eu corro sudo python3 reverse.py. Eu aceito sua resposta.
— αғsнιη

Perfeito! Obrigado por uma questão legal, que descreve uma situação Provavelmente todos nós já esteve em :)
— Jacob Vlijm

Nota: Se algum arquivo na origem sobrescreveu um arquivo no destino por ter o mesmo nome, você não pode simplesmente desfazê-lo, e esse script apenas o exclui. A suposição aqui é que não houve conflitos de nome quando você fez a inicial cp.
— precisa saber é o seguinte

@neon_overload Correto, editei na minha resposta.
— Jacob Vlijm

Isso não funciona cp -r. Eu mudei os.removecom print, e ele está produzindo um monte de arquivos que não existem. Suponho que esteja faltando os subdiretórios e listando apenas os arquivos no final.
— Typewar

7

TL; DR:

Todos os arquivos que estão presentes nos dois srce destpodem ser removidos destassim:

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

Para uma explicação passo a passo, veja abaixo.

Simplificando o problema:

Para entender o que o comando que queremos desfazer realmente fez, começamos por simplificá-lo:

O comando que queremos desfazer é

sudo cp From_SOURCE/* To_DESTINATION/

Para entender como desfazer, sudonão é relevante.

Vou usar os nomes de diretório srcpara From_SOURCEe destpara To_DESTINATION.

Agora, nosso comando é:

cp src/* dest/

Se srccontém os arquivos f1, f2e f3, e os diretórios d1e d2, o shell expande esse comando para:

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

Sem opções como -r, -Rou -a, o comando cpnão copia diretórios.
Isso significa que o comando os deixará de fora, mostrando um erro para cada um deles:

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

Isso significa que apenas copiamos arquivos simples e nenhum diretório para dest.

Decidindo quais arquivos remover:

Possivelmente havia arquivos com desto mesmo nome que arquivos src. Nesse caso, os arquivos foram substituídos (1). É tarde demais para eles, desculpe. Recupere-os do backup mais recente.

Em relação aos arquivos existentes, queremos remover apenas os arquivos que foram copiados. Esses arquivos existem nos dois diretórios, com o mesmo nome e o mesmo conteúdo.

Então, procuramos esses arquivos:

Primeiro, cdem src, porque faz as seguintes findcomandos muito mais simples, e definir uma variável para o caminho absoluto do dest:

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

Em seguida, listamos todos os arquivos no src:

$ find . -maxdepth 1 -type f

e, para cada arquivo encontrado, use cmppara verificar se há um arquivo com o mesmo conteúdo em dest:

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

Removendo os arquivos, com cuidado:

Esses arquivos são os que queremos remover. Mas para ter certeza, nós os movemos para um diretório diferente primeiro - e examinamos os comandos antes de executá-los:

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

Parece bom! Agora podemos deixar echode executar os mvcomandos reais :

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

Todos os arquivos destcopiados srce ainda os mesmos em srce destagora estão em /tmp/toDelete/e podem ser removidos depois de uma última olhada.


Notas:
(1) Verifique se cphá um alias mais cp -iou menos, que teria evitado sobrescrever arquivos perguntando primeiro.


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.