Existe-t-il un moyen de supprimer des fichiers d'un dossier qui se trouvent dans un autre dossier?

21

Disons que je copie et colle des fichiers à partir du dossier A, qui comprend:

Dossier A:

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

dans le dossier B, qui après la mise à jour, a:

Dossier B:

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

Existe-t-il un moyen de supprimer tous les fichiers du dossier A qui se trouvent dans le dossier B (marqués d'un *)? En plus de les sélectionner manuellement et de les supprimer, ou de faire un Ctrl-Z juste après le copier-coller

Je préférerais une méthode Windows ou un logiciel qui pourrait le faire

Merci!

DarkFire13
la source
4
Comment savez-vous que ce sont les mêmes fichiers en termes de contenu? Je ne peux pas imaginer un scénario où vous voudriez considérer aveuglément un fichier comme un doublon basé uniquement sur le nom du fichier.
rory.ap
@roryap Je pense que cette question a été posée car OP a copié les fichiers du dossier 1 vers le dossier 2, a remplacé tout et pense maintenant, hmm, c'était une erreur, mais se rend compte que le lendemain, donc l'annulation n'est pas possible. Mais vous avez raison, contentwize vous ne pouvez pas savoir.
LPChip
13
Juste une question stupide ... Pourquoi ne pas utiliser "couper" et "coller"?
DaMachk
@DaMachk si vous travaillez avec des lecteurs réseau ou des supports amovibles, copier-> vérifier-> le nettoyage est une voie raisonnable. Si les fichiers sont utilisés par un processus, ce pourrait être une bonne idée de le tester sur une copie (je le fais avec des fichiers pour l'analyse des données python en cas de bogues dans mon propre code qui encombrent le fichier d'entrée (par exemple). Il peut ne pas être aussi nécessaire qu'avant, mais de vieilles habitudes et tout ça. Sinon, l'OP pourrait avoir mal cliqué sur la copie au lieu de la couper,
Chris H

Réponses:

35

Il existe un logiciel gratuit appelé WinMerge . Vous pouvez utiliser ce logiciel pour faire correspondre les doublons. Tout d'abord, utilisez FileOpen, et choisissez les deux répertoires, avec le dossier contenant les fichiers que vous souhaitez conserver à gauche et ceux que vous n'avez pas à droite. Ensuite, allez View, et désactivez l' option Show Different Items, Show Left Unique Itemset Show Right Unique Items. Cela ne laissera que les fichiers identiques dans la liste. Après cela, choisissez EditSelect All, faites un clic droit sur n'importe quel fichier, puis cliquez sur DeleteRight. Cela supprimera les doublons du dossier de droite.

démo de WinMerge

phyrfox
la source
L'avantage de cette méthode est qu'elle peut détecter si les fichiers ne sont pas similaires en termes de contenu, si cela est important. WinMerge peut comparer tous les facteurs importants à un seul.
25

Cela peut être fait via la ligne de commande en utilisant la commande forfiles

Supposons que le dossier A se trouve dans c:\temp\Folder Aet le dossier B se trouve dansc:\temp\Folder B

La commande serait alors:

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

Après cela, le dossier B supprimera tous les fichiers présents dans le dossier A. N'oubliez pas que si le dossier B contient des fichiers portant le même nom, mais pas le même contenu, ils seront toujours supprimés.

Il est possible d'étendre cela pour qu'il fonctionne également avec des dossiers dans des sous-dossiers, mais par crainte que cela devienne compliqué et inutile, j'ai décidé de ne pas le publier. Cela nécessiterait les options / s et @relpath (et des tests supplémentaires sur xD)

LPChip
la source
11

Vous pouvez utiliser ce script 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}
}

J'espère que c'est assez explicite. Il examine chaque élément du dossier B, vérifie s'il existe un élément du même nom dans le dossier A et, dans l'affirmative, il supprime l'élément du dossier A. Notez que la finale \dans les chemins de dossier est importante.

Version une ligne:

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

Si vous ne vous souciez pas si vous obtenez un déluge d'erreurs rouges dans la console, vous pouvez supprimer le -EA 'SilentlyContinue'.

Enregistrez-le sous forme de .ps1fichier, par exemple dedupe.ps1. Avant de pouvoir exécuter des scripts PowerShell, vous devez activer leur exécution:

Set-ExecutionPolicy Unrestricted -Scope CurrentUser

Vous pourrez ensuite l'invoquer avec .\dedupe.ps1lorsque vous serez dans le dossier qui le contient.

Ben N
la source
4

rsync

rsyncest un programme utilisé pour synchroniser le répertoire. Parmi les nombreuses (vraiment nombreuses) options que vous avez, il y a l'explication --ignore-non-existing, --remove-source-fileset --recursive.

Tu peux faire

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

si nous supposons que vous avez les fichiers dans le répertoire A (4) et 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
la source
4

La réponse de LPChip est la meilleure.

Mais parce que j'ai commencé à apprendre Python, je me suis dit: "Heck, pourquoi ne pas écrire un script Python comme réponse à cette question?"

Installer Python et Send2Trash

Vous devez installer Python avant de pouvoir exécuter le script à partir de la ligne de commande.

Ensuite, installez Send2Trash pour que les fichiers supprimés ne disparaissent pas irrémédiablement mais finissent dans la corbeille du système d'exploitation:

pip install Send2Trash

Créer un script

Créez un nouveau fichier avec par exemple le nom DeleteDuplicateInFolderA.py

Copiez le script suivant dans le fichier.

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

Usage

Mode de fonctionnement à sec, qui vous montre quels fichiers seraient supprimés sans supprimer aucun fichier:

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

Mode de suppression de fichiers, qui supprime en effet les fichiers, alors faites attention:

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

Sortie du mode marche à sec

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

Sortie du mode de suppression de fichier

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 de l'unité

Si vous souhaitez tester l'application ci-dessus, créez un fichier nommé DeleteDuplicateInFolderATest.pyet collez-y ces tests:

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
la source
Pouvez-vous me dire pourquoi ce script est "moche comme l'enfer"? Je viens de le lire et ce que vous faites est limpide. Je suis presque tenté de le coller sur CodeReview.SE pour savoir ce qui n'est pas préféré à ce sujet.
user1717828
Ajouter une somme md5 pour vérifier si le contenu des fichiers est le même serait une bonne option. Utiliser également le mécanisme de corbeille du système d'exploitation au lieu de le supprimer.
lolesque
@ user1717828: J'ai restructuré le code, supprimé ce commentaire et pris votre suggestion de publier le code sur CodeReview.SE .
Lernkurve
@lolesque: partie Send2Trash: terminé. Merci pour l'idée!
Lernkurve
1
@barlop, je répondais au message d'origine, pas à un commentaire.
user1717828
1

Utiliser bash

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

Bien sûr, vous pouvez être plus sûr en vérifiant si le fichier est là ou en vérifiant si le nom de fichier est sûr. Mais en supposant que vous vouliez simplement faire cela, et que vous n'avez pas de fichiers nommés de manière ridicule folderB- c'est un moyen rapide et sale de le faire. (et vous pouvez utiliser l'émulateur bash fourni avec git , si vous n'exécutez pas Win10 + bash)

rm-vanda
la source
Peut-être que vous devez ajouter une vérification si vous trouvez des répertoires ...
Hastur
1

Tout programme de style CN, comme Total Commander, a une commande de différence de répertoire qui sélectionne les fichiers dans les deux onglets qui sont différents de l'autre onglet. Appelez cette commande, tabdans le plus grand répertoire (B), inversez la sélection à l'aide de *et supprimez. Cela a l'avantage de ne pas supprimer les fichiers qui peuvent avoir changé (d'une manière ou d'une autre) et ne sont pas les mêmes bien qu'ils soient d'accord sur le nom. Vous pouvez utiliser la même commande de répertoire diff pour les localiser après la suppression.

Je suppose que je suis coincé dans les années 90 ... mais je n'ai rien vu de plus élégant depuis :-) Jusqu'à présent, c'est la seule réponse qui nécessite aussi peu que 5 touches et aucune script / ligne de commande.

The Vee
la source
1

Disons que je copie et colle des fichiers du dossier A dans le dossier B.

Existe-t-il un moyen de supprimer tous les fichiers du dossier A qui se trouvent dans le dossier B? En plus de les sélectionner manuellement et de les supprimer, ou de faire un Ctrl-Z juste après le copier-coller

Méthode Windows

Si vous avez toujours besoin de copier des fichiers d'un emplacement vers un autre, puis assurez-vous ensuite que les fichiers qui ont été copiés avec succès sont également supprimés de l'emplacement source d'origine, voici ci-dessous une solution de script par lots que vous pouvez utiliser pour automatiser l'ensemble de la tâche avec juste un cliquez simplement sur chaque course.

  • Assurez - vous de définir les SourceDiret les des DestDirvariables en conséquence pour vos besoins.

  • De plus, dans la partie du script ci-dessous, ("%SourceDir%\*.*") DOvous pouvez simplement modifier la *.*valeur pour être plus explicite pour les noms de fichiers ( File A.txt) ou les extensions de fichiers ( *.wav) selon les besoins.


@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

Autres ressources

Pimp Juice IT
la source