Apakah ada cara untuk menghapus file dari folder yang ada di folder lain?

21

Katakanlah saya menyalin dan menempel file dari folder A, yang meliputi:

Map A:

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

ke dalam folder B, yang setelah diperbarui, memiliki:

Map B:

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

Apakah ada cara untuk menghapus semua file dari folder A yang ada di folder B (ditandai dengan *)? Selain secara manual memilih masing-masing dan menghapusnya, atau ctrl-Z'ing tepat setelah salin-tempel

Saya lebih suka metode windows atau beberapa perangkat lunak yang bisa melakukan ini

Terima kasih!

DarkFire13
sumber
4
Bagaimana Anda tahu mereka file yang sama konten-bijaksana? Saya tidak bisa membayangkan skenario di mana Anda ingin secara membabi buta menganggap file sebagai duplikat hanya berdasarkan nama file saja.
rory.ap
@roryap Saya pikir pertanyaan ini muncul karena OP menyalin file dari folder 1 ke folder 2, mengganti semua dan sekarang berpikir, hmm, ini adalah kesalahan, tetapi menyadari bahwa pada hari berikutnya, jadi membatalkan tidak mungkin. Tapi Anda benar, konten tidak dapat Anda ketahui.
LPChip
13
Hanya pertanyaan bodoh ... Mengapa tidak menggunakan "cut" dan "paste"?
DaMachk
@DaMachk jika Anda bekerja dengan drive jaringan atau media yang dapat dipindahkan, salin-> verifikasi-> pembersihan adalah rute yang masuk akal. Jika file digunakan oleh beberapa proses, mungkin ide yang baik untuk mengujinya pada salinan (saya melakukan ini dengan file untuk analisis data python jika ada bug dalam kode saya sendiri yang menghancurkan file input (misalnya). Mungkin saja tidak seperlunya dulu, tetapi kebiasaan lama dan semua itu. Atau OP bisa saja salah meng-copy, bukan memotong,
Chris H

Jawaban:

35

Ada perangkat lunak gratis di luar sana yang disebut WinMerge . Anda dapat menggunakan perangkat lunak ini untuk mencocokkan duplikat. Pertama, gunakan FileOpen, dan pilih kedua direktori, dengan folder dengan file yang ingin Anda simpan di sebelah kiri, dan yang Anda tidak di sebelah kanan. Lalu, ke View, dan membatalkan pilihan Show Different Items, Show Left Unique Items, dan Show Right Unique Items. Ini akan meninggalkan hanya file identik yang tersisa dalam daftar. Setelah itu, pilih EditSelect All, klik kanan pada file apa pun, dan klik pada DeleteRight. Ini akan menghapus duplikat dari folder sebelah kanan.

demo dari WinMerge

phyrfox
sumber
Manfaat dari metode ini adalah dapat mendeteksi jika file tidak serupa konten-bijaksana, jika ini penting. WinMerge dapat membandingkan semua faktor yang penting.
25

Ini dapat dilakukan melalui commandline dengan menggunakan perintah forfiles

Mari kita asumsikan Anda memiliki Folder A terletak di c:\temp\Folder A, dan Folder B terletak dic:\temp\Folder B

Perintahnya adalah:

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

Setelah ini selesai, Folder B akan menghapus semua file yang ada di Folder A. Perlu diingat, bahwa jika folder B memiliki file dengan nama yang sama, tetapi bukan konten yang sama, mereka masih akan dihapus.

Dimungkinkan untuk memperluas ini agar berfungsi dengan folder di dalam subfolder juga, tetapi karena khawatir hal ini menjadi tidak perlu rumit, saya telah memutuskan untuk tidak mempostingnya. Ini akan membutuhkan opsi / s dan @relpath (dan pengujian lebih lanjut xD)

LPChip
sumber
11

Anda dapat menggunakan skrip PowerShell ini:

$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}
}

Semoga ini cukup jelas. Itu terlihat pada setiap item di Folder B, memeriksa apakah ada item dengan nama yang sama di Folder A, dan jika demikian, ia menghapus item Folder A. Perhatikan bahwa final \di jalur folder penting.

Versi satu baris:

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

Jika Anda tidak peduli apakah Anda mendapatkan kesalahan merah di konsol, Anda dapat menghapus -EA 'SilentlyContinue'.

Simpan sebagai .ps1file, mis dedupe.ps1. Sebelum Anda dapat menjalankan skrip PowerShell, Anda harus mengaktifkan eksekusinya:

Set-ExecutionPolicy Unrestricted -Scope CurrentUser

Maka Anda akan dapat memintanya dengan .\dedupe.ps1ketika Anda berada di folder yang berisi itu.

Ben N
sumber
4

rsync

rsyncadalah program yang digunakan untuk menyinkronkan direktori. Dari banyak (sangat banyak) pilihan yang Anda miliki, ada penjelasan sendiri --ignore-non-existing, --remove-source-filesdan --recursive.

Anda dapat melakukan

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

jika kami mengira Anda memiliki file di direktori A (4) dan B (4 + 2).

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


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

Jawaban LPChip adalah yang lebih baik.

Tetapi karena saya sudah mulai belajar Python, saya berpikir, "Heck, mengapa tidak menulis skrip Python sebagai jawaban untuk pertanyaan ini?"

Instal Python dan Send2Trash

Anda harus menginstal Python sebelum Anda dapat menjalankan skrip dari baris perintah.

Kemudian instal Send2Trash sehingga file yang dihapus tidak hilang tetapi berakhir di tempat sampah OS:

pip install Send2Trash

Buat skrip

Buat file baru dengan misalnya nama DeleteDuplicateInFolderA.py

Salin skrip berikut ke dalam file.

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

Pemakaian

Mode dry run, yang menunjukkan kepada Anda file mana yang akan dihapus tanpa benar-benar menghapus file apa pun:

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

Mode penghapusan file, yang memang menghapus file, jadi berhati-hatilah:

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

Output mode lari kering

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

Output dari mode penghapusan file

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

Tes unit

Jika Anda ingin menguji aplikasi di atas, buat file dengan nama DeleteDuplicateInFolderATest.pydan rekatkan unittests ini ke dalamnya:

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()
Lernkurve
sumber
Bisakah Anda memberi tahu saya mengapa skrip ini "jelek sekali"? Saya baru saja membacanya dan apa yang Anda lakukan sangat jelas. Saya hampir tergoda untuk menempelkannya di CodeReview.SE untuk belajar tentang apa yang tidak disukai tentangnya.
user1717828
Menambahkan md5sum untuk memeriksa apakah konten file sama akan menjadi opsi yang bagus. Juga menggunakan mekanisme sampah OS alih-alih menghapus.
lolesque
@ user1717828: Saya telah merestrukturisasi kode, menghapus komentar itu dan mengambil saran Anda untuk memposting kode di CodeReview.SE .
Lernkurve
@lolesque: Bagian Send2Trash: selesai. Terima kasih atas idenya!
Lernkurve
1
@barlop, saya membalas ke posting asli, bukan komentar.
user1717828
1

Menggunakan bash

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

Tentu Anda bisa lebih aman dengan memeriksa apakah file itu ada, atau memeriksa apakah nama file aman. Tetapi dengan asumsi Anda hanya ingin menyelesaikan ini, dan tidak memiliki file dengan nama konyol folderB- ini adalah cara cepat dan kotor untuk menyelesaikannya. (dan Anda dapat menggunakan emulator bash yang datang dengan git , jika Anda tidak menjalankan Win10 + bash)

rm-vanda
sumber
Mungkin Anda perlu menambahkan cek jika Anda menemukan direktori ...
Hastur
1

Setiap program NC-style, seperti Total Commander, memiliki perintah perbedaan direktori yang memilih file di kedua tab yang berbeda dari tab lainnya. Panggil perintah ini, tabke direktori yang lebih besar (B), membalikkan pemilihan menggunakan *dan menghapus. Ini memiliki keuntungan karena tidak menghapus file yang mungkin telah berubah (entah bagaimana) dan tidak sama meskipun mereka sepakat namanya. Anda dapat menggunakan perintah diff direktori yang sama untuk menemukan ini setelah penghapusan.

Saya kira saya terjebak di tahun sembilan puluhan ... tapi saya belum benar-benar melihat sesuatu yang lebih elegan sejak :-) Sejauh ini adalah satu-satunya jawaban yang hanya membutuhkan sekitar 5 penekanan tombol dan tidak ada scripting / command line sama sekali.

Vee
sumber
1

Katakanlah saya menyalin dan menempel file dari folder A ke folder B.

Apakah ada cara untuk menghapus semua file dari folder A yang ada di folder B? Selain secara manual memilih masing-masing dan menghapusnya, atau ctrl-Z'ing tepat setelah salin-tempel

Metode Windows

Jika Anda selalu perlu menyalin file dari satu lokasi ke lokasi lain dan kemudian memastikan file yang berhasil disalin juga dihapus dari lokasi sumber asli, maka di bawah ini adalah solusi skrip batch yang dapat Anda gunakan untuk mengotomatiskan seluruh tugas itu hanya dengan klik sederhana setiap proses.

  • Pastikan untuk mengatur SourceDirdan DestDirvariabel sesuai dengan kebutuhan Anda.

  • Selain itu, di bagian skrip di bawah ini ("%SourceDir%\*.*") DOAnda hanya dapat mengubah *.*nilai menjadi lebih eksplisit untuk nama file ( File A.txt) atau ekstensi file ( *.wav) sesuai kebutuhan.


@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

Sumber Daya Lebih Lanjut

Pimp Juice
sumber