Czy istnieje sposób na usunięcie plików z folderu, który znajduje się w innym folderze?

21

Powiedzmy, że kopiuję i wklejam pliki z folderu A, który obejmuje:

Folder A:

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

do folderu B, który po aktualizacji ma:

Folder B:

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

Czy istnieje sposób na usunięcie wszystkich plików z folderu A znajdujących się w folderze B (oznaczonych *)? Oprócz ręcznego wybierania każdego z nich i usuwania go, lub wciśnięcia Ctrl-Z zaraz po kopiowaniu i wklejeniu

Wolałbym metodę Windows lub oprogramowanie, które mogłoby to zrobić

dzięki!

DarkFire13
źródło
4
Skąd wiesz, że pod względem zawartości są to te same pliki? Nie wyobrażam sobie scenariusza, w którym chciałbyś na ślepo uznać plik za duplikat oparty tylko na samej nazwie pliku.
rory.ap
@roryap Myślę, że to pytanie powstało, ponieważ OP skopiował pliki z folderu 1 do folderu 2, zastąpił wszystko i teraz myśli, hmm, to był błąd, ale zdaje sobie sprawę, że następnego dnia, więc cofnięcie nie jest możliwe. Ale masz rację, contentwize, którego nie znasz.
LPChip
13
Tylko głupie pytanie ... Dlaczego nie użyć „wytnij” i „wklej”?
DaMachk
@ DaMachk, jeśli pracujesz z dyskami sieciowymi lub nośnikami wymiennymi, kopiowanie-> weryfikacja-> czyszczenie to rozsądna droga. Jeśli pliki są używane przez jakiś proces, dobrym pomysłem może być przetestowanie ich na kopii (robię to z plikami do analizy danych python w przypadku błędów w moim własnym kodzie blokującym plik wejściowy (na przykład). nie były już tak konieczne, jak dawniej, ale stare nawyki i tak dalej. Alternatywnie OP mógł błędnie kliknąć kopię zamiast wyciąć,
Chris H

Odpowiedzi:

35

Istnieje darmowe oprogramowanie o nazwie WinMerge . Możesz użyć tego oprogramowania do dopasowania duplikatów. Najpierw użyj FileOpeni wybierz oba katalogi, z folderem z plikami, które chcesz zachować po lewej, i tymi, których nie chcesz po prawej stronie. Następnie przejdź do Viewi odznacz Show Different Items, Show Left Unique Itemsoraz Show Right Unique Items. Spowoduje to pozostawienie identycznych plików pozostałych na liście. Następnie wybierz EditSelect All, kliknij prawym przyciskiem myszy dowolny plik i kliknij DeleteRight. Spowoduje to usunięcie duplikatów z folderu po prawej stronie.

demo WinMerge

phyrfox
źródło
Zaletą tej metody jest to, że może wykryć, czy pliki nie są podobne pod względem zawartości, jeśli jest to ważne. WinMerge może porównać wszystkie istotne czynniki do jednego.
25

Można to zrobić za pomocą wiersza polecenia za pomocą polecenia forfiles

Załóżmy, że masz folder A w c:\temp\Folder Afolderze, a folder B wc:\temp\Folder B

Poleceniem byłoby wtedy:

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

Po wykonaniu tej czynności w folderze B zostaną usunięte wszystkie pliki znajdujące się w folderze A. Należy pamiętać, że jeśli folder B zawiera pliki o tej samej nazwie, ale nie o tej samej treści, nadal zostaną usunięte.

Można to rozszerzyć, aby działało również z folderami w podfolderach, ale z obawy, że stanie się to niepotrzebnie skomplikowane, postanowiłem nie publikować. Wymagałoby to opcji / s i @relpath (oraz dalszego testowania xD)

LPChip
źródło
11

Możesz użyć tego skryptu 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}
}

Mam nadzieję, że jest to dość oczywiste. Sprawdza każdy element w folderze B, sprawdza, czy w folderze A jest element o tej samej nazwie, a jeśli tak, usuwa element z folderu A. Pamiętaj, że końcowy \w ścieżkach folderów jest ważny.

Wersja jednowierszowa:

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

Jeśli nie obchodzi Cię, czy w konsoli pojawi się zalew czerwonych błędów, możesz usunąć -EA 'SilentlyContinue'.

Zapisz go jako .ps1plik, np dedupe.ps1. Przed uruchomieniem skryptów PowerShell musisz włączyć ich wykonywanie:

Set-ExecutionPolicy Unrestricted -Scope CurrentUser

Następnie będziesz mógł ją wywołać, .\dedupe.ps1gdy znajdziesz się w folderze, który ją zawiera.

Ben N.
źródło
4

rsync

rsyncto program służący do synchronizacji katalogu. Od wielu (naprawdę wielu) opcje masz tam są siebie wyjaśniając --ignore-non-existing, --remove-source-filesi --recursive.

Możesz to zrobić

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

jeśli przypuszczamy, że masz pliki w katalogu A (4) i 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
Hastur
źródło
4

Odpowiedź LPChip jest lepsza.

Ale ponieważ zacząłem uczyć się języka Python, pomyślałem: „Do licha, dlaczego nie napisać skryptu Python jako odpowiedzi na to pytanie?”.

Zainstaluj Python i Send2Trash

Musisz zainstalować Python, zanim będziesz mógł uruchomić skrypt z wiersza poleceń.

Następnie zainstaluj Send2Trash, aby usunięte pliki nie zniknęły bezpowrotnie, ale trafiły do ​​kosza systemu operacyjnego:

pip install Send2Trash

Utwórz skrypt

Utwórz nowy plik, na przykład o nazwie DeleteDuplicateInFolderA.py

Skopiuj następujący skrypt do pliku.

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

Stosowanie

Tryb suchego uruchamiania, który pokazuje, które pliki zostaną usunięte bez usuwania plików:

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

Tryb usuwania plików, który rzeczywiście usuwa pliki, więc bądź ostrożny:

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

Wyjście z trybu pracy suchej

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

Wyjście z trybu usuwania plików

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

Test jednostkowy

Jeśli chcesz przetestować powyższą aplikację, utwórz plik o nazwie DeleteDuplicateInFolderATest.pyi wklej do niego następujące wpisy:

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
źródło
Czy możesz mi powiedzieć, dlaczego ten skrypt jest „brzydki jak diabli”? Właśnie to przeczytałem i to, co robisz, jest krystalicznie czyste. Niemal mam ochotę wkleić go na CodeReview.SE, aby dowiedzieć się, co nie jest w nim preferowane.
user1717828,
Dobrym rozwiązaniem byłoby dodanie sumy md5 do sprawdzenia, czy zawartość plików jest taka sama. Również przy użyciu mechanizmu kosza systemu operacyjnego zamiast usuwania.
lolesque
@ user1717828: Zrestrukturyzowałem kod, usunąłem ten komentarz i przyjąłem twoją sugestię opublikowania kodu w CodeReview.SE .
Lernkurve
@lolesque: Send2Trash part: done. Dziękuję za pomysł!
Lernkurve
1
@barlop, odpowiadałem na oryginalny post, a nie na komentarz.
user1717828,
1

Korzystanie z bash

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

Na pewno możesz być bardziej bezpieczny, sprawdzając, czy plik tam jest, lub sprawdzając, czy nazwa pliku jest bezpieczna. Ale zakładając, że po prostu chcesz to zrobić i nie masz żadnych śmiesznie nazwanych plików folderB- jest to szybki i brudny sposób na zrobienie tego. (i możesz użyć emulatora bash dostarczonego z git , jeśli nie korzystasz z bash Win10 +)

rm-vanda
źródło
Może musisz dodać czek, jeśli znajdziesz katalogi ...
Hastur
1

Każdy program w stylu NC, taki jak Total Commander, ma polecenie różnic w katalogu, które wybiera pliki na obu kartach, które różnią się od innych kart. Wywołaj to polecenie tabdo większego katalogu (B), odwróć wybór za pomocą *i usuń. Ma to tę zaletę, że nie usuwa plików, które mogły się zmienić (jakoś) i nie są takie same, chociaż zgadzają się z nazwą. Możesz użyć tej samej komendy diff katalogu, aby zlokalizować je po usunięciu.

Wydaje mi się, że utknąłem w latach dziewięćdziesiątych ... ale tak naprawdę nie widziałem nic bardziej eleganckiego od :-) Jak dotąd jest to jedyna odpowiedź, która wymaga zaledwie 5 naciśnięć klawiszy i żadnego skryptu / wiersza poleceń.

The Vee
źródło
1

Powiedzmy, że kopiuję i wklejam pliki z folderu A do folderu B.

Czy istnieje sposób na usunięcie wszystkich plików z folderu A znajdujących się w folderze B? Oprócz ręcznego wybierania każdego z nich i usuwania go, lub wciśnięcia Ctrl-Z zaraz po kopiowaniu i wklejeniu

Metoda Windows

Jeśli zawsze musisz skopiować pliki z jednej lokalizacji do drugiej, a następnie upewnić się, że pliki, które zostały pomyślnie skopiowane, zostaną również usunięte z oryginalnej lokalizacji źródłowej, poniżej znajduje się rozwiązanie skryptu wsadowego, którego można użyć do zautomatyzowania całego zadania za pomocą wystarczy kliknąć każdy bieg.

  • Pamiętaj, aby ustawić SourceDira DestDirzmienne odpowiednio do swoich potrzeb.

  • Dodatkowo, w części skryptu poniżej, ponieważ ("%SourceDir%\*.*") DOmożesz po prostu zmienić *.*wartość, aby była bardziej wyraźna dla nazw plików ( File A.txt) lub rozszerzeń plików ( *.wav) w razie potrzeby.


@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

Dalsze zasoby

Pimp Juice IT
źródło