Có cách nào để loại bỏ các tập tin từ một thư mục trong một thư mục khác?


21

Giả sử tôi sao chép và dán các tệp từ thư mục A, bao gồm:

Thư mục A:

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

vào thư mục B, sau khi cập nhật, có:

Thư mục B:

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

Có cách nào để xóa tất cả các tệp khỏi thư mục A trong thư mục B (được đánh dấu *) không? Bên cạnh việc chọn thủ công từng cái và xóa nó, hoặc ctrl-Z'ing ngay sau khi sao chép-dán

Tôi thích một phương pháp windows hoặc một số phần mềm có thể làm điều này

cảm ơn!


4
Làm thế nào để bạn biết chúng là cùng một tập tin nội dung khôn ngoan? Tôi không thể tưởng tượng ra một kịch bản mà bạn muốn mù quáng coi một tệp là một bản sao chỉ dựa trên tên tệp.
rory.ap

@roryap Tôi nghĩ rằng câu hỏi này đã được đặt ra vì OP đã sao chép các tệp từ thư mục 1 sang thư mục 2, thay thế tất cả và bây giờ nghĩ rằng, hmm, đây là một lỗi, nhưng nhận ra rằng ngày hôm sau, vì vậy không thể hoàn tác. Nhưng bạn đã đúng, nội dung bạn không thể biết.
LPChip

13
Chỉ là một câu hỏi ngớ ngẩn ... Tại sao không sử dụng "cắt" và "dán"?
DaMachk

@DaMachk nếu bạn đang làm việc với các ổ đĩa mạng hoặc phương tiện lưu động, sao chép-> xác minh-> dọn dẹp là một lộ trình hợp lý. Nếu các tệp được sử dụng bởi một số quy trình, có thể là một ý tưởng tốt để kiểm tra nó trên một bản sao (tôi làm điều này với các tệp để phân tích dữ liệu python trong trường hợp có lỗi trong mã của riêng tôi ghi đè tệp đầu vào (ví dụ). không cần thiết như trước đây, nhưng thói quen cũ và tất cả những thứ đó. Ngoài ra, OP có thể đã bấm nhầm vào bản sao thay vì cắt,
Chris H

Câu trả lời:


35

Có phần mềm miễn phí ngoài đó gọi là WinMerge . Bạn có thể sử dụng phần mềm này để ghép các bản sao. Đầu tiên, sử dụng FileOpenvà chọn cả hai thư mục, với thư mục chứa các tệp bạn muốn giữ ở bên trái và các thư mục bạn không ở bên phải. Sau đó, đi đến View, và bỏ chọn Show Different Items, Show Left Unique ItemsShow Right Unique Items. Điều này sẽ chỉ để lại các tập tin giống hệt còn lại trong danh sách. Sau đó, chọn EditSelect All, nhấp chuột phải vào bất kỳ tệp nào và nhấp vào DeleteRight. Điều này sẽ xóa các bản sao khỏi thư mục bên phải.

bản demo của WinMerge


Lợi ích của phương pháp này là nó có thể phát hiện nếu các tệp không giống nhau về nội dung, nếu điều này quan trọng. WinMerge có thể so sánh tất cả các yếu tố quan trọng với một.

25

Điều này có thể được thực hiện thông qua dòng lệnh bằng cách sử dụng lệnh forfiles

Giả sử bạn có Thư mục A nằm trong c:\temp\Folder Avà Thư mục B nằm trongc:\temp\Folder B

Lệnh sau đó sẽ là:

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

Sau khi hoàn thành, Thư mục B sẽ xóa tất cả các tệp có trong Thư mục A. Hãy nhớ rằng nếu thư mục B có các tệp có cùng tên, nhưng không cùng nội dung, chúng sẽ vẫn bị xóa.

Cũng có thể mở rộng nó để hoạt động với các thư mục trong các thư mục con, nhưng vì sợ điều này trở nên phức tạp không cần thiết, tôi đã quyết định không đăng nó. Nó sẽ yêu cầu các tùy chọn / s và @relpath (và thử nghiệm thêm xD)


11

Bạn có thể sử dụng tập lệnh PowerShell này:

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

Hy vọng rằng nó khá tự giải thích. Nó xem xét mọi mục trong Thư mục B, kiểm tra xem có một mục có cùng tên trong Thư mục A hay không và nếu có, nó sẽ xóa mục Thư mục A. Lưu ý rằng cuối cùng \trong đường dẫn thư mục là quan trọng.

Phiên bản một dòng:

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

Nếu bạn không quan tâm liệu bạn có nhận được lỗi đỏ trong bảng điều khiển hay không, bạn có thể xóa -EA 'SilentlyContinue'.

Lưu nó dưới dạng một .ps1tập tin, ví dụ dedupe.ps1. Trước khi bạn có thể chạy các tập lệnh PowerShell, bạn sẽ cần kích hoạt thực thi chúng:

Set-ExecutionPolicy Unrestricted -Scope CurrentUser

Sau đó, bạn sẽ có thể gọi nó .\dedupe.ps1khi bạn đang ở trong thư mục chứa nó.


4

rsync

rsynclà một chương trình được sử dụng để đồng bộ hóa thư mục. Từ nhiều lựa chọn (thực sự rất nhiều) bạn có, bạn có thể tự giải thích --ignore-non-existing, --remove-source-files--recursive.

Bạn có thể làm

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

nếu chúng tôi cho rằng bạn có các tệp trong thư mục A (4) và 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

4

Câu trả lời của LPChip là câu trả lời tốt hơn.

Nhưng bởi vì tôi đã bắt đầu học Python, tôi nghĩ, "Heck, tại sao không viết một kịch bản Python làm câu trả lời cho câu hỏi này?"

Cài đặt Python và Send2Trash

Bạn cần cài đặt Python trước khi có thể chạy tập lệnh từ dòng lệnh.

Sau đó cài đặt Send2Trash để các tệp bị xóa không bị xóa một cách đáng tiếc nhưng cuối cùng lại nằm trong thùng rác của HĐH:

pip install Send2Trash

Tạo tập lệnh

Tạo một tệp mới với ví dụ tên DeleteDuplicateInFolderA.py

Sao chép đoạn script sau vào tập tin.

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

Sử dụng

Chế độ chạy khô, cho bạn biết những tệp nào sẽ bị xóa mà không thực sự xóa bất kỳ tệp nào:

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

Chế độ xóa tệp, thực sự xóa tệp, vì vậy hãy cẩn thận:

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

Đầu ra của chế độ chạy khô

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

Đầu ra của chế độ xóa tập tin

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

Kiểm tra đơn vị

Nếu bạn muốn kiểm tra ứng dụng ở trên, hãy tạo một tệp có tên DeleteDuplicateInFolderATest.pyvà dán những điều không mong muốn này vào 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()

Bạn có thể cho tôi biết lý do tại sao kịch bản này là "xấu như địa ngục"? Tôi chỉ đọc qua nó và những gì bạn đang làm là rõ ràng. Tôi gần như muốn dán nó lên CodeReview.SE để tìm hiểu về những gì không được ưa thích về nó.
dùng1717828

Thêm md5sum để kiểm tra xem nội dung tệp có giống nhau không sẽ là một lựa chọn tốt. Cũng sử dụng cơ chế rác hệ điều hành thay vì loại bỏ.
lolesque

@ user1717828: Tôi đã cấu trúc lại mã, xóa nhận xét đó và lấy đề xuất của bạn để đăng mã lên CodeReview.SE .
Lernkurve

@lolesque: Phần Send2Trash: đã xong. Cảm ơn bạn cho ý tưởng!
Lernkurve

1
@barlop, tôi đã trả lời bài viết gốc, không phải bình luận.
dùng1717828

1

Sử dụng bash

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

Chắc chắn bạn có thể an toàn hơn bằng cách kiểm tra xem tệp có ở đó không, hoặc kiểm tra xem tên tệp có an toàn không. Nhưng giả sử bạn chỉ muốn thực hiện việc này và không có bất kỳ tệp nào được đặt tên lố bịch trong folderB- đây là một cách nhanh chóng và bẩn thỉu để hoàn thành nó. (và bạn có thể sử dụng trình giả lập bash đi kèm với git , nếu bạn không chạy Win10 + bash)


Có lẽ bạn cần thêm một kiểm tra nếu bạn tìm thấy các thư mục ...
Hastur

1

Bất kỳ chương trình kiểu NC nào, như Total Commander, đều có lệnh chênh lệch thư mục chọn các tệp trong cả hai tab khác với tab khác. Gọi lệnh này, tabđến thư mục lớn hơn (B), đảo ngược lựa chọn bằng cách sử dụng *và xóa. Điều này có lợi thế là không xóa các tệp có thể đã thay đổi (bằng cách nào đó) và không giống như mặc dù chúng đồng ý về tên. Bạn có thể sử dụng cùng một lệnh diff thư mục để xác định vị trí này sau khi xóa.

Tôi đoán rằng tôi bị mắc kẹt trong những năm chín mươi ... nhưng tôi chưa thực sự thấy điều gì thanh lịch hơn kể từ :-) Cho đến nay, đây là câu trả lời duy nhất yêu cầu ít nhất là khoảng 5 lần nhấn phím và không có dòng lệnh / kịch bản nào.


1

Giả sử tôi sao chép và dán các tệp từ thư mục A vào thư mục B.

Có cách nào để xóa tất cả các tệp khỏi thư mục A trong thư mục B không? Bên cạnh việc chọn thủ công từng cái và xóa nó, hoặc ctrl-Z'ing ngay sau khi sao chép-dán

Phương pháp Windows

Nếu bạn luôn cần sao chép tệp từ vị trí này sang vị trí khác và sau đó đảm bảo các tệp được sao chép thành công cũng bị xóa khỏi vị trí nguồn ban đầu, thì bên dưới là giải pháp tập lệnh bó mà bạn có thể sử dụng để tự động hóa toàn bộ tác vụ đó chỉ bằng một nhấp chuột đơn giản mỗi lần chạy.

  • Hãy chắc chắn để đặt SourceDirvà các DestDirbiến phù hợp cho nhu cầu của bạn.

  • Ngoài ra, trong phần của tập lệnh bên dưới, ("%SourceDir%\*.*") DObạn có thể chỉ cần thay đổi *.*giá trị để rõ ràng hơn cho tên tệp ( File A.txt) hoặc phần mở rộng tệp ( *.wav) nếu cần.


@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

Tài nguyên khác

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.