20

Допустим, я копирую и вставляю файлы из папки A, которая включает в себя:

Папка А:

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

в папку B, которая после обновления имеет:

Папка Б:

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

Есть ли способ удалить все файлы из папки A, которые находятся в папке B (помечены *)? Помимо ручного выбора каждого из них и его удаления, или ctrl-Z'ing сразу после копирования-вставки

Я бы предпочел либо метод Windows или какое-то программное обеспечение, которое может сделать это

Спасибо!

8 ответов8

34

Там есть свободное программное обеспечение под названием WinMerge. Вы можете использовать это программное обеспечение для сопоставления дубликатов. Сначала выберите « File → « Open и выберите обе директории: слева - папка с файлами, которые вы хотите сохранить, а справа - нет. Затем перейдите в « View и отмените выбор « Show Different Items , « Show Left Unique Items и « Show Right Unique Items . Это оставит только идентичные файлы, оставленные в списке. После этого выберите « Edit → « Select All , щелкните правой кнопкой мыши любой файл и выберите « Delete → « Right . Это удалит дубликаты из правой папки.

демо WinMerge

24

Это можно сделать через командную строку с помощью команды forfiles

Предположим, у вас есть папка A, расположенная в папке c:\temp\Folder A , а папка B - в папке c:\temp\Folder B

Команда будет тогда:

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

После того, как это будет сделано, в папке B будут удалены все файлы, которые присутствуют в папке A. Имейте в виду, что если в папке 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, и, если это так, удаляет элемент папки 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()
1

Использование Bash

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

Конечно, вы можете быть более безопасным, проверив, существует ли файл, или проверив, является ли имя файла безопасным. Но при условии, что вы просто хотите это сделать, и не имеете никаких нелепо названных файлов в folderB - это быстрый и грязный способ сделать это. (и вы можете использовать эмулятор bash, который поставляется с git, если вы не используете Win10 + bash)

1

Допустим, я копирую и вставляю файлы из папки A в папку B.

Есть ли способ удалить все файлы из папки A, которые находятся в папке 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

Дополнительные ресурсы

0

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

Я думаю, что застрял в девяностых ... но я не видел ничего более элегантного с тех пор :-) Пока что это единственный ответ, который требует всего лишь 5 нажатий клавиш и никаких скриптов / командной строки вообще.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .