web-dev-qa-db-fra.com

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

Supposons que je copie et colle des fichiers 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é 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 soit une méthode Windows, soit un logiciel capable de le faire.

merci!

21
DarkFire13

Il existe un logiciel libre appelé WinMerge . Vous pouvez utiliser ce logiciel pour faire correspondre les doublons. Commencez par utiliser FileOpen et choisissez les deux répertoires, avec le dossier contenant les fichiers que vous souhaitez conserver à gauche et ceux que vous ne conservez pas à droite. Ensuite, allez à View et désélectionnez Show Different Items, Show Left Unique Items et Show Right Unique Items. Cela ne laissera que les fichiers identiques laissés dans la liste. Ensuite, choisissez EditSelect All, cliquez avec le bouton droit de la souris sur n’importe quel fichier, puis cliquez sur DeleteRight. Cela supprimera les doublons du dossier de droite.

demo of WinMerge

34
phyrfox

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

Supposons que vous avez le dossier A situé dans c:\temp\Folder A et le dossier B situé dans c:\temp\Folder B

La commande serait alors:

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

Une fois cette opération terminée, tous les fichiers présents dans le dossier A seront supprimés du dossier B. N'oubliez pas que, si le dossier B contient des fichiers portant le même nom mais pas le même contenu, ils seront tout de même supprimés.

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

25
LPChip

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 si un élément du même nom figure dans le dossier A et, le cas échéant, supprime l'élément du dossier A. Notez que le \ final dans les chemins de dossiers est important.

Version à une ligne:

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

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

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

Set-ExecutionPolicy Unrestricted -Scope CurrentUser

Ensuite, vous pourrez l'invoquer avec .\dedupe.ps1 lorsque vous êtes dans le dossier qui le contient.

11
Ben N

rsync

rsync est un programme utilisé pour synchroniser un répertoire. Parmi les nombreuses (très nombreuses) options que vous avez, il y a --ignore-non-existing, --remove-source-files et --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 les répertoires 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
4
Hastur

La réponse de LPChip est la meilleure.

Mais comme j'ai commencé à apprendre le python, je me suis dit: "Pourquoi ne pas écrire un script Python pour répondre à 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 soient pas irrémédiablement disparus mais se retrouvent 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 __== "__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 d'exécution à sec, qui vous indique quels fichiers seraient supprimés sans supprimer aucun fichier:

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

Le mode de suppression de fichier, qui supprime effectivement des fichiers, soyez donc prudent:

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

Sortie du mode de fonctionnement à 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.py et collez-y ces unittests:

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 __== '__main__':
    main()
4
Lernkurve

Utilisation de bash

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

Bien sûr, vous pourriez être plus en sécurité en vérifiant si le fichier est présent ou en vérifiant si le nom du fichier est sûr. Mais en supposant que vous souhaitiez simplement que cela soit fait et que vous n’ayez pas de fichiers nommés de façon ridicule dans 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)

1
rm-vanda

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

Est-il possible de supprimer tous les fichiers du dossier A qui se trouvent dans le dossier B? Outre la sélection manuelle de chaque élément et sa suppression, ou la combinaison de touches Ctrl-Z après le copier-coller

Méthode Windows

Si vous devez toujours copier des fichiers d'un emplacement à un autre, puis vous assurer que les fichiers copiés avec succès sont également supprimés de l'emplacement source d'origine, vous trouverez ci-dessous une solution de script par lots que vous pouvez utiliser pour automatiser toute la tâche avec juste une tâche. simple clic à chaque exécution.

  • Veillez à définir les variables SourceDir et DestDir en fonction de vos besoins.

  • De plus, dans la partie du script ci-dessous en tant que ("%SourceDir%\*.*") DO, vous pouvez simplement changer la valeur de *.* pour qu'elle soit plus explicite pour les noms de fichier (File A.txt) ou les extensions de fichier (*.wav) selon vos 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

Ressources supplémentaires

1
Pimp Juice IT

Tout programme de type CN, comme Total Commander, possède une commande de différence de répertoire qui sélectionne des fichiers différents dans les deux onglets. Appelez cette commande, tab, dans 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 aient un nom identique. Vous pouvez utiliser la même commande de répertoire directory pour les localiser après la suppression.

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

0
The Vee