Чи є спосіб видалити файли з папки, яка знаходиться в іншій папці?


21

Скажімо, я копіюю та вставляю файли з папки А, яка включає:

Папка A:

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

у папку B, яка після оновлення має:

Папка B:

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

Чи є можливість видалити всі файли з папки А, які знаходяться в папці B (позначена символом *)? Крім того, що вибираєте кожен з них вручну і видаляєте його, або ctrl-Z'ing відразу після вставки-копії

Я б віддав перевагу або метод Windows, або якесь програмне забезпечення, яке могло це зробити

Дякую!


4
Звідки ти знаєш, що вони однакові за змістом файли? Я не уявляю сценарій, коли ви хочете сліпо вважати файл дублікатом лише на основі лише імені файлу.
rory.ap

@roryap Я думаю, що це питання виникло, тому що ОП скопіювало файли з папки 1 у папку 2, замінило все і тепер думає, хм, це була помилка, але розуміє, що наступного дня, тому скасувати це неможливо. Але ти маєш рацію, contentwize, якого ти не можеш знати.
LPChip

13
Просто німе запитання ... Чому б не використовувати "вирізати" та "вставити"?
DaMachk

@DaMachk, якщо ви працюєте з мережевими накопичувачами або знімними носіями, копія-> підтвердити-> очищення - розумний шлях. Якщо файли використовуються деяким процесом, може бути гарною ідеєю протестувати його на копії (я це роблю з файлами для аналізу даних python у разі помилок у власному коді, клобіруючи вхідний файл (наприклад). не такий необхідний, як це було раніше, але старі звички і все таке. Крім того, ОП могла б неправильно натиснути копію замість вирізаного,
Кріс Х

Відповіді:


34

Там є безкоштовне програмне забезпечення під назвою WinMerge . Ви можете використовувати це програмне забезпечення для зіставлення дублікатів. По-перше, використовуйте FileOpenі вибирайте обидва каталоги з папкою з файлами, які ви хочете зберегти зліва, і тими, яких ви не маєте праворуч. Потім перейдіть Viewі зніміть прапорець Show Different Items, Show Left Unique Itemsі Show Right Unique Items. Це залишить у списку лише однакові файли. Після цього виберіть EditSelect All, клацніть правою кнопкою миші на будь-якому файлі та натисніть DeleteRight. Це видалить дублікати з правої папки.

демонстрація програми WinMerge


Перевага цього методу полягає в тому, що він може виявити, якщо файли не схожі на зміст, якщо це важливо. WinMerge може порівняти всі важливі фактори до одного.

25

Це можна зробити за допомогою командної лінії за допомогою команди forfiles

Припустимо, у вас розміщена папка А c:\temp\Folder A, а в папці Вc:\temp\Folder B

Командою буде:

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

Після цього в папці B будуть видалені всі файли, які містяться в папці А. Майте на увазі, що якщо в папці B є файли з тим самим іменем, але не однакового вмісту, вони все одно будуть видалені.

Можна також розширити це на роботу з папками в підпапках, але, побоюючись, щоб це не стало зайвим ускладненням, я вирішив не публікувати його. Для цього знадобляться параметри / s та @relpath (та подальше тестування xD)


11

Ви можете використовувати цей сценарій PowerShell:

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

Сподіваємось, це досить зрозуміло. Він переглядає кожен елемент у папці B, перевіряє, чи є в папці A елемент з тим самим іменем, і якщо так, то видаляє елемент папки А. Зауважте, що остаточний \шлях у папці важливий.

Однорядкова версія:

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

Якщо вам не байдуже, чи виникають у вас консолі червоних помилок, ви можете видалити цю -EA 'SilentlyContinue'.

Збережіть його як .ps1файл, наприклад dedupe.ps1. Перш ніж запустити сценарії PowerShell, вам потрібно включити їх виконання:

Set-ExecutionPolicy Unrestricted -Scope CurrentUser

Тоді ви зможете викликати його, .\dedupe.ps1коли ви знаходитесь в папці, яка його містить.


4

rsync

rsyncце програма, яка використовується для синхронізації каталогу. З багатьох (насправді багатьох) варіантів у вас є самопояснення --ignore-non-existing, --remove-source-filesі --recursive.

Ви можете зробити

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

якщо ми припустимо, що у вас є файли в каталозі A (4) і 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

Відповідь LPChip - краща.

Але оскільки я почав вивчати Python, я подумав: "Чорт, чому б не написати сценарій Python як відповідь на це питання?"

Встановіть Python та Send2Trash

Вам потрібно буде встановити Python, перш ніж ви зможете запустити скрипт з командного рядка.

Потім встановіть Send2Trash, щоб видалені файли не зникли безповоротно, а потрапили у смітник ОС:

pip install Send2Trash

Створення сценарію

Створіть новий файл, наприклад, ім'я DeleteDuplicateInFolderA.py

Скопіюйте у файл наступний сценарій.

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

Використання

Режим сухого запуску, який показує, які файли буде видалено без фактичного видалення жодних файлів:

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

Режим видалення файлів, який дійсно видаляє файли, тому будьте уважні:

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

Виведення режиму сухого ходу

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

Виведення режиму видалення файлів

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

Тест одиниці

Якщо ви хочете протестувати програму вище, створіть файл з ім'ям DeleteDuplicateInFolderATest.pyі вставте в нього ці тести одиниці:

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()

Чи можете ви сказати мені, чому цей сценарій "некрасивий як пекло"? Я щойно прочитав це, і те, що ви робите, є кришталево зрозумілим. Я майже спокусився вставити його на CodeReview.SE, щоб дізнатися про те, що йому не вдається.
користувач1717828

Додавання md5sum для перевірки того, чи вміст файлів однаковий, було б непоганим варіантом. Також використовуйте механізм сміття ОС замість видалення.
лолеск

@ user1717828: Я реструктуризував код, видалив цей коментар і прийняв вашу пропозицію опублікувати код на CodeReview.SE .
Лернкурве

@lolesque: Send2Trash частина: виконано. Дякую за ідею!
Лернкурве

1
@barlop, я відповідав на оригінальний пост, а не на коментар.
користувач1717828

1

Використання bash

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

Впевнені, що ви можете бути більш безпечними, перевіривши, чи файл там, або перевіривши, чи ім’я файлу безпечне. Але якщо припустити, що ви просто хочете це зробити, і не маєте смішно названих файлів folderB- це швидкий і брудний спосіб зробити це. (і ви можете використовувати емулятор bash, який постачається з git , якщо ви не запускаєте Win10 + bash)


Можливо, вам потрібно додати чек, якщо ви знайдете каталоги ...
Hastur

1

Будь-яка програма в стилі NC, як-от Total Commander, має команду різниці каталогів, яка вибирає файли на обох вкладках, які відрізняються від інших вкладок. Викличте цю команду tabу більший каталог (B), інвертуйте вибір за допомогою *та видаліть. Це має перевагу в тому, що не видаляти файли, які, можливо, якось змінилися і не є такими ж, хоча вони погоджуються в імені. Ви можете використовувати ту саму команду diff, щоб знайти їх після видалення.

Я думаю, що я застряг у дев'яностих ... але я ще не бачив нічого більш елегантного з тих пір :-) Поки що це єдина відповідь, на яку потрібно лише 5 натискань клавіш і ніяких сценаріїв / командного рядка.


1

Скажімо, я копіюю та вставляю файли з папки А в папку B.

Чи є спосіб видалити всі файли з папки А, які знаходяться в папці B? Крім того, що вибираєте кожен з них вручну і видаляєте його, або ctrl-Z'ing відразу після вставки-копії

Метод Windows

Якщо вам завжди потрібно скопіювати файли з одного місця в інше, а потім переконатися, що файли, які були скопійовані успішно, також видаляються з вихідного місця розташування джерела, то нижче наведено пакетне рішення сценарію, яке ви можете використовувати для автоматизації цього завдання лише простий клік кожного запуску.

  • Не забудьте встановити відповідні SourceDirта DestDirзмінні відповідно до ваших потреб.

  • Крім того, у нижченаведеній частині сценарію ("%SourceDir%\*.*") DOви можете просто змінити *.*значення, щоб воно було більш явним для імен файлів ( File A.txt) або розширень файлів ( *.wav) за потреби.


@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

Подальші ресурси

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.