Dosyaları başka bir klasörde bulunan bir klasörden kaldırmanın bir yolu var mı?


21

Diyelim ki aşağıdakileri içeren A klasöründeki dosyaları kopyalayıp yapıştırıyorum:

Klasör A:

file1.cfg  
file2.txt  
file3.esp  
file4.bsa  

Güncellemeden sonra B klasöründe:

B klasörü:

apples.mp3  
file1.cfg    *
file2.txt    *
file3.esp    *
file4.bsa    *
turtles.jpg

Tüm dosyaları A klasöründeki B klasöründeki (* ile işaretlenmiş) silmek için bir yol var mı? Her birini manuel olarak seçip silmek ya da kopyala yapıştır işleminden hemen sonra ctrl-Z'ing'in yanında

Windows yöntemini veya bunu yapabilecek bazı yazılımları tercih ederim

Teşekkürler!


4
İçerik olarak aynı dosyalar olduğunu nereden biliyorsunuz? Sadece bir dosyayı yalnızca bir dosyaya dayanarak bir dosyayı bir kopya olarak göz önünde bulundurmak isteyeceğiniz bir senaryo düşünemiyorum.
rory.ap

@roryap Bence bu sorun ortaya çıktı, çünkü OP dosyaları 1. klasörden 2. klasöre kopyaladı, hepsini değiştirdi ve şimdi düşünüyor, hmm, bunun bir hata olduğunu, ancak ertesi gün, yani geri almanın mümkün olmadığını fark ediyor. Ama haklısın, bilemezsin.
LPChip

13
Sadece aptal bir soru ... Neden "kes" ve "yapıştır" kullanmıyorsunuz?
DaMachk

@DaMachk eğer ağ sürücüleri veya çıkarılabilir medya ile çalışıyorsanız, kopyala> doğrula-> temizlik makul bir yoldur. Eğer dosyalar bazı işlemler tarafından kullanılıyorsa, bir kopya üzerinde test etmek iyi bir fikir olabilir (giriş dosyasını clobbering yaparken kendi kodumda hatalar olması durumunda python veri analizi için dosyalar ile yapıyorum) (örneğin). eskisi gibi değil, eski alışkanlıklar ve her şeyden daha önemli değil, alternatif olarak OP, kesmek yerine yanlış tıklanmış bir kopyaya sahip olabilir,
Chris H

Yanıtlar:


35

WinMerge adında özgür bir yazılım var . Bu yazılımı, kopyaları eşleştirmek için kullanabilirsiniz. Öncelikle, File→ öğesini kullanın Openve her iki dizini de seçin; solda tutmak istediğiniz dosyaları içeren klasör ve sağda olmayanlar. Sonra gidin Viewve seçimi bırak Show Different Items, Show Left Unique Itemsve Show Right Unique Items. Bu sadece listede kalan aynı dosyaları bırakacaktır. Bundan sonra, Edit→ seçeneğini seçin Select All, herhangi bir dosyaya sağ tıklayın ve Delete→ seçeneğine tıklayın Right. Bu, kopyaları sağdaki klasörden siler.

WinMerge demosu


Bu yöntemin yararı, dosyaların içerik bakımından benzer olmadığını, önemli olup olmadığını tespit edebilmesidir. WinMerge, önemli olan tüm faktörleri birebir karşılaştırabilir.

25

Bu komut kullanılarak komut satırı üzerinden yapılabilir. forfiles

Klasör A'nın içinde c:\temp\Folder Ave Klasör B'nin içinde olduğunu varsayalım .c:\temp\Folder B

Komut şöyle olur:

c:\>forfiles /p "c:\temp\Folder A" /c "cmd /c del c:\temp\Folder B\@file"

Bu yapıldıktan sonra, B Klasörü A Klasöründe bulunan tüm dosyaların kaldırılmasını sağlayacaktır. B klasörünün aynı ada sahip ancak aynı içeriğe sahip olmayan dosyaları varsa, bunların silinmeye devam edeceğini unutmayın.

Bunu, alt klasörlerdeki klasörlerle de çalışacak şekilde genişletmek mümkündür, ancak bunun gereksiz bir şekilde karmaşık olması korkusuyla, göndermeye karşı karar verdim. / S ve @relpath seçeneklerini gerektiriyor (ve xD'yi daha fazla test ediyor)


11

Bu PowerShell betiğini kullanabilirsiniz:

$folderA = 'C:\Users\Ben\test\a\' # Folder to remove cross-folder duplicates from
$folderB = 'C:\Users\Ben\test\b\' # Folder to keep the last remaining copies in
Get-ChildItem $folderB | ForEach-Object {
    $pathInA = $folderA + $_.Name
    If (Test-Path $pathInA) {Remove-Item $pathInA}
}

Umarım oldukça açıklamalıdır. Klasör B'deki her öğeye bakar, Klasör A'da aynı ada sahip bir öğenin olup olmadığını kontrol eder ve öyleyse Klasör A öğesini kaldırır. Nihai unutmayın \klasör yolları önemlidir.

Tek satır sürümü:

gci 'C:\Users\Ben\test\b\' | % {del ('C:\Users\Ben\test\a\' + $_.Name) -EA 'SilentlyContinue'}

Konsolda bir tutam kırmızı hata olup olmadığını umursanız, kaldırabilirsiniz -EA 'SilentlyContinue'.

Bir .ps1dosya olarak kaydedin , örneğin dedupe.ps1. PowerShell scriptlerini çalıştırabilmeniz için, onların çalıştırılmasını etkinleştirmeniz gerekir:

Set-ExecutionPolicy Unrestricted -Scope CurrentUser

Sonra onu içeren .\dedupe.ps1klasörün içindeyken onu çağırabilirsin .


4

rsync

rsyncdizini senkronize etmek için kullanılan bir programdır. Sahip olduğunuz birçok (gerçekten çok) seçeneklerinden orada açıklayan öz vardır --ignore-non-existing, --remove-source-filesve --recursive.

Yapabilirsin

rsync -avr --ignore-non-existing --recursive --remove-source-files   B/ A -v

varsayalım ki, A (4) ve B (4 + 2) dizinindeki dosyalara sahipsiniz.

A       B
├── a   ├── a
├── b   ├── b
├── c   ├── c
└── d   ├── d
        ├── e
        └── f     # Before


A       B
├── a   ├── e
├── b   └── f
├── c   
└── d             # After

4

LPChip’in cevabı daha iyi.

Ama Python'u öğrenmeye başladığım için, "Heck, neden bu soruyu cevaplamak için bir Python senaryosu yazmıyorsunuz?" Diye düşündüm.

Python ve Send2Trash'i yükleyin

Komut dosyasını komut satırından çalıştırmadan önce Python'u kurmanız gerekir.

Ardından, Send2Trash'i yükleyin, böylece silinen dosyalar geri alınamaz şekilde giderilemez , ancak işletim sisteminin çöp kutusuna atılır :

pip install Send2Trash

Komut dosyası oluştur

Örneğin ismiyle yeni bir dosya oluşturun DeleteDuplicateInFolderA.py

Aşağıdaki betiği dosyaya kopyalayın.

#!/usr/bin/python

import sys
import os
from send2trash import send2trash


class DeleteDuplicateInFolderA(object):
    """Given two paths A and B, the application determines which files are in
       path A which are also in path B and then deletes the duplicates from
       path A.

       If the "dry run" flag is set to 'true', files are deleted. Otherwise
       they are only displayed but not deleted.
    """

    def __init__(self, path_A, path_B, is_dry_run=True):
        self._path_A = path_A
        self._path_B = path_B
        self._is_dry_run = is_dry_run

    def get_filenames_in_folder(self, folder_path):
        only_files = []
        for (dirpath, dirnames, filenames) in os.walk(folder_path):
            only_files.extend(filenames)
        return only_files

    def print_files(sel, heading, files):
        print(heading)
        if len(files) == 0:
            print("   none")
        else:
            for file in files:
                print("   {}".format(file))

    def delete_duplicates_in_folder_A(self):
        only_files_A = self.get_filenames_in_folder(self._path_A)
        only_files_B = self.get_filenames_in_folder(self._path_B)

        files_of_A_that_are_in_B = [file for file in only_files_A if file in only_files_B]

        self.print_files("Files in {}".format(self._path_A), only_files_A)
        self.print_files("Files in {}".format(self._path_B), only_files_B)

        if self._is_dry_run:
            self.print_files("These files would be deleted: ", [os.path.join(self._path_A, file) for file in files_of_A_that_are_in_B])
        else:
            print("Deleting files:")
            for filepath in [os.path.join(self._path_A, file) for file in files_of_A_that_are_in_B]:
                print("   {}".format(filepath))
                # os.remove(filepath)  # Use this line instead of the next if Send2Trash is not installed
                send2trash(filepath)

if __name__ == "__main__":
    if len(sys.argv) == 4:
        is_dry_run_argument = sys.argv[3]
        if not is_dry_run_argument == "--dryrun":
            println("The 3rd argument must be '--dryrun' or nothing.")
        else:
            app = DeleteDuplicateInFolderA(sys.argv[1], sys.argv[2], is_dry_run=True)
    else:
        app = DeleteDuplicateInFolderA(sys.argv[1], sys.argv[2], is_dry_run=False)
    app.delete_duplicates_in_folder_A()

kullanım

Herhangi bir dosyayı silmeden hangi dosyaların silineceğini gösteren kuru çalışma modu:

c:\temp> python .\DeleteDuplicateInFolderA.py c:\temp\test\A c:\temp\test\B --dryrun

Dosyaları silme işlevi olan dosya silme modu, bu nedenle dikkatli olun:

c:\temp> python .\DeleteDuplicateInFolderA.py c:\temp\test\A c:\temp\test\B

Kuru çalışma modu çıkışı

Files in C:\temp\A
  1.txt
  2.txt
Files in C:\temp\B
  2.txt
  3.txt
These files would be deleted:
  C:\temp\A\2.txt

Dosya silme modunun çıktısı

Files in C:\temp\A
  1.txt
  2.txt
Files in C:\temp\B
  2.txt
  3.txt
Deleting files:
  C:\temp\A\2.txt

Ünite testi

Yukarıdaki uygulamayı test etmek istiyorsanız, adında bir dosya oluşturun DeleteDuplicateInFolderATest.pyve bu en küçükleri yapıştırın:

import unittest
import os
import shutil
from DeleteDuplicateInFolderA import DeleteDuplicateInFolderA


class DeleteDuplicateInFolderATest(unittest.TestCase):

    def __init__(self, *args, **kwargs):
        super(DeleteDuplicateInFolderATest, self).__init__(*args, **kwargs)
        self._base_directory = r"c:\temp\test"
        self._path_A = self._base_directory + r"\A"
        self._path_B = self._base_directory + r"\B"

    def create_folder_and_create_some_files(self, path, filename_list):
        if os.path.exists(path):
            shutil.rmtree(path)
        os.makedirs(path)
        for filename in filename_list:
            open(os.path.join(path, filename), "w+").close()

    def setUp(self):
        # Create folders and files for testing
        self.create_folder_and_create_some_files(self._path_A, ["1.txt", "2.txt"])
        self.create_folder_and_create_some_files(self._path_B, ["2.txt", "3.txt"])

    def tearDown(self):
        for path in [self._path_A, self._path_B, self._base_directory]:
            if os.path.exists(path):
                shutil.rmtree(path)

    def test_duplicate_file_gets_deleted(self):
        # Arrange
        app = DeleteDuplicateInFolderA(self._path_A, self._path_B, is_dry_run=False)

        # Act
        app.delete_duplicates_in_folder_A()

        # Assert
        self.assertFalse(os.path.isfile(self._path_A + r"\2.txt"), "File 2.txt has not been deleted.")

    def test_duplicate_file_gets_not_deleted_in_mode_dryrun(self):
        # Arrange
        app = DeleteDuplicateInFolderA(self._path_A, self._path_B, is_dry_run=True)

        # Act
        app.delete_duplicates_in_folder_A()

        # Assert
        self.assertTrue(os.path.isfile(self._path_A + r"\2.txt"), "File 2.txt should not have been deleted in mode '--dryrun'")

def main():
    unittest.main()

if __name__ == '__main__':
    main()

Neden bu senaryo "cehennem gibi çirkin" diyebilir misin? Ben sadece okudum ve yaptığınız şey çok net. Neyin tercih edilmediğini öğrenmek için neredeyse CodeReview.SE'ye yapıştırmaya başlıyorum.
user1717828

Dosya içeriğinin aynı olup olmadığını kontrol etmek için bir md5sum eklemek iyi bir seçenek olacaktır. Ayrıca kaldırmak yerine OS çöp kutusu mekanizmasını kullanarak .
lolesque

@ user1717828: Kodu yeniden yapılandırdım, bu yorumu sildim ve kodu CodeReview.SE'ye göndermek için önerinizi aldım .
Lernkurve

@lolesque: Send2Trash bölüm: bitti. Fikir için teşekkürler!
Lernkurve

1
@barlop, Ben bir yorum değil, asıl gönderiye cevap veriyordum.
user1717828

1

Bash kullanarak

for f in $(ls /path/to/folderB/); do 
    rm -rf /path/to/folderA/$f
done

Dosyanın olup olmadığını kontrol ederek veya dosya adının güvenli olup olmadığını kontrol ederek daha güvenli olacağınızdan emin olun. Ancak sadece bunu yapmak istediğinizi ve saçma sapan olarak adlandırılmış dosyalara sahip olmadığınızı varsayalım folderB- bu işlemin gerçekleştirilmesi için hızlı ve kirli bir yoldur. (ve eğer Win10 + bash kullanmıyorsanız, git ile gelen bash emülatörünü kullanabilirsiniz )


Belki dizinler bulursanız bir çek eklemeniz gerekir ...
Hastur

1

Total Commander gibi herhangi bir NC tarzı programda, her iki sekmedeki diğer sekmeden farklı olan dosyaları seçen bir dizin farkı komutu vardır. Bu komutu tabdaha büyük dizine (B) çağırır, seçimi kullanarak *ve siler. Bu, bir şekilde değişmiş (bir şekilde) değiştirilmiş dosyaları silmeme avantajına sahiptir ve adında aynı fikirde olsalar da aynı değildir. Silme işleminden sonra bunları bulmak için aynı dizin diff komutunu kullanabilirsiniz.

Sanırım doksanlı yıllarda mahsur kaldım ... ama daha önce gerçekten daha zarif bir şey görmedim :-) Şimdiye kadar bu, 5 tuşa basma kadar az ve hiçbir komut dosyası / komut satırı gerektirmeyen tek cevap.


1

Diyelim ki A klasöründeki dosyaları B klasörüne kopyalayıp yapıştırıyorum.

A klasöründeki tüm dosyaları B klasöründe silmek için bir yolu var mı? Her birini manuel olarak seçip silmek ya da kopyala yapıştır işleminden hemen sonra ctrl-Z'ing'in yanında

Windows Yöntemi

Dosyaları her zaman bir konumdan diğerine kopyalamanız gerekiyorsa ve daha sonra başarılı bir şekilde kopyalanan dosyaların orijinal kaynak konumundan da silindiğinden emin olursanız, aşağıda bu görevi tümüyle otomatikleştirmek için kullanabileceğiniz bir toplu komut dosyası çözümü verilmiştir. Her çalıştırma basit tıklayın.

  • SourceDirVe DestDirdeğişkenlerini ihtiyaçlarınıza göre ayarladığınızdan emin olun .

  • Ek olarak, aşağıdaki betiğin bölümünde ("%SourceDir%\*.*") DO, sadece *.*dosya adları ( File A.txt) veya dosya uzantıları ( *.wav) için gerektiğinde daha belirgin olacak şekilde değeri değiştirebilirsiniz .


@ECHO ON
SET SourceDir=C:\Users\User\Desktop\Source
SET DestDir=C:\Users\User\Desktop\Dest

FOR %%A IN ("%SourceDir%\*.*") DO XCOPY /F /Y "%%~A" "%DestDir%\" && DEL /Q /F "%%~A"
GOTO EOF

Ek Kaynaklar

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.