Kopyalama (cp) komut eylemini geri alma


14

Kaynak klasördeki bazı dosyaları terminaldeki feryat komut satırını kullanarak hedef klasöre kopyaladım.

sudo cp From_SOURCE/* To_DESTINATION/

Şimdi bu komutu geri almak istiyorum.


Anladığımdan emin değilim. Sadece kopya kaldırılsın mı? (sudo rm dosyası)
Jacob Vlijm

@JacobVlijm işlemi geri almak değil ayrı bir komuttur. Kopyalamadıysam, önerdiğin komutu daha önce kullanabilirdim. Ve kopyalanan 1000'den fazla dosyayı silmek için daha fazla zaman bu komutu kullanmak zorunda?
αғsнιη

@KasiyA - Bir seçenek, seçilen tüm dosya adlarını bulmak From_SOURCE/*ve bunlardan kaldırmak olabilir To_DESTINATION/; Bu bash ile yapılabilir - burada sorunlar cp komutu bir şey üzerine yazdı olabilir, semboller kopyalandı, adları boşluklu dosyalar, vb - böylece sorunları olabilir ve biraz tuhaf olabilir. Mükemmel bir 'geri al' seçeneği birçok şeyi hesaba katmak zorunda kalabilir.
Wilf

Yanıtlar:


13

İyi anlarsam, durum şöyle:

  • Varolan bir dizine (muhtemelen büyük) sayıda dosya kopyaladınız ve işlemi tersine çevirmeniz gerekiyor.
  • Hedeflenen dizin, orada tutmanız gereken bir dizi başka dosya içerir , bu da tüm dosyaları dizinden kaldırmayı imkansız hale getirir

Aşağıdaki komut dosyası orijinal (kaynak) dizine bakar ve bu dosyaları listeler. Ardından, dosyaları kopyaladığınız dizine bakar ve yalnızca listelenen dosyaları kaynak dizinde bulundukları gibi kaldırır.

tryEleman elle zaten bazı dosyaları kaldırılmış olabilir veya kaynak dizinden tüm dosyalar hedefe kopyalanan olsaydı durumda örneğin, hataları önlemek için eklenir. Sudo ayrıcalıklarına ihtiyacınız varsa, komut dosyasını "sudo" ile çalıştırın (aşağıya bakın).

Senaryo

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

Nasıl kullanılır

  • Komut dosyasını boş bir dosyaya yapıştırın, kaydedin reverse.py,
  • Kaynak ve hedef klasör için doğru yolları ekleyin,
  • Kolaylık nedenleriyle çalıştırılabilir yapın,
  • Komut ile çalıştırın:

    [sudo] /path/to/reverse.py
    

Uyarı

İlk olarak, neyi başarmanız gerektiğini iyi anladıysam bir test dizininde deneyin!


Kaynaklı dizin "düz" ise

Kaynak dizinin alt dizini yoksa, komut dosyası daha da basit olabilir:

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

Not

Kopyalama eylemi , hedefte benzer şekilde adlandırılmış bir dosyanın üzerine yazılırsa (değiştirilirse), dosya kaldırılır, ancak orijinal dosya (elbette) komut dosyası tarafından geri getirilmez. Varsayım, hiçbir isim çatışması olmadığıdır.


İşe yarıyor, teşekkürler. Ben idare ediyorum sudo python3 reverse.py. Cevabınızı kabul ediyorum.
αғsнιη

Mükemmel! Muhtemelen hepimizin içinde bulunduğu bir durumu anlatan güzel bir soru için teşekkür ederim :)
Jacob Vlijm

Not: Kaynaktaki herhangi bir dosya, aynı ada sahip olduğu için hedefteki bir dosyanın üzerine yazdıysa , bunu kaldıramazsınız ve bu komut dosyası yalnızca siler. Buradaki varsayım, ilkini yaptığınızda hiçbir isim çatışması olmadığıdır cp.
thomasrutter

@neon_overload Doğru, cevabımda düzenledi.
Jacob Vlijm

Bu işe yaramaz cp -r. Değiştim os.removeile printve var olmayan dosyaların bir demet çıkışı oluyor. Ben alt dizinleri eksik ve sadece sonunda dosyaları listeleme varsayıyorum.
Daktilo

7

TL; DR:

Her ikisinde de bulunan srcve destşu şekilde kaldırılabilen tüm dosyalar dest:

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

Adım adım açıklama için aşağıya bakın.

Sorunu basitleştirme:

Geri almak istediğimiz komutun gerçekte ne yaptığını anlamak için, onu basitleştirerek başlıyoruz:

Geri almak istediğimiz komut

sudo cp From_SOURCE/* To_DESTINATION/

Nasıl geri alınacağını anlamak için sudoönemli değildir.

Ben dizin adlarını kullanacağız srciçin From_SOURCEve destiçin To_DESTINATION.

Şimdi emrimiz:

cp src/* dest/

Eğer srcdosyaları içeren f1, f2ve f3, ve dizinleri d1ve d2kabuk için bu komutu genişletir:

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

Seçenekleri gibi olmadan -r, -Rya da -akomut cpdizinleri kopyalamaz.
Bu, komutun her biri için bir hata göstererek onları dışarıda bırakacağı anlamına gelir:

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

Bu, yalnızca basit dosyaları kopyaladık ve dizinleri kopyalayamadık dest.

Hangi dosyaların kaldırılacağına karar verme:

Muhtemelen içindeki dosyalarla destaynı adda dosyalar vardı src. Bu durumda dosyaların üzerine yazılmıştır (1). Onlar için çok geç, üzgünüm. En son yedeklemeden geri alın.

Orada bulunan dosyalar ile ilgili olarak, yalnızca kopyalanan dosyaları kaldırmak istiyoruz. Bu dosyalar her iki dizinde de aynı ada ve aynı içeriğe sahiptir.

Bu yüzden bu dosyaları ararız:

İlk olarak, cdiçine giriyoruz src, çünkü aşağıdaki findkomutları daha basit hale getiriyor ve dest'in mutlak yoluna bir değişken ayarlıyor:

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

Ardından, src içindeki tüm dosyaları listeleriz:

$ find . -maxdepth 1 -type f

ve bulunan her dosya için cmp, dest'de aynı içeriğe sahip bir dosya olup olmadığını kontrol etmek için kullanın :

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

Dosyaları dikkatlice kaldırma:

Bu dosyalar kaldırmak istediğimiz dosyalardır. Ancak emin olmak için önce onları farklı bir dizine taşıyoruz ve çalıştırmadan önce komutlara bakıyoruz:

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

İyi görünüyor! Şimdi echogerçek mvkomutları çalıştırmak için dışarıda bırakabiliriz :

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

Tüm dosyalar desto kopyalanan srcve hala aslında aynı srcve dest, şimdi /tmp/toDelete/, ve son bir kez göz aldıktan sonra kaldırılabilir.


Notlar:
(1) Önce sorarak dosyaların üzerine yazılmasını engelleyen cpbir takma ad olup olmadığını kontrol edin cp -i.


5

Bu eski, ama sadece saf bir bash cevabı göndermek istedim:

İlk önce dosyaları kopyaladığınız dizine geçin.

cd dest

Sonra, lskaynak dizin ve çıktı içine borurm

ls source | xargs rm


2
ayrıştırma lsgenellikle kötü bir fikirdir. mywiki.wooledge.org/ParsingLs Gönderinizi aşağıya indirmeyeceğim, ancak not edilmelidir.
Sergiy Kolodyazhnyy

@SergiyKolodyazhnyy iyi bir nokta. Asla daha az: rm `ls`—Önceki boş bir klasör için ve dosyaların boşluk ve satırsonu içermeyen adları olduğunda.
Multifix
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.