C'è un modo per rimuovere i file da una cartella che si trova in un'altra cartella?


21

Diciamo che copio e incollo i file dalla cartella A, che include:

Cartella A:

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

nella cartella B, che dopo l'aggiornamento ha:

Cartella B:

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

C'è un modo per eliminare tutti i file dalla cartella A che si trovano nella cartella B (contrassegnata con un *)? Oltre a selezionare manualmente ciascuno di essi e cancellarlo, o ctrl-Z'ing subito dopo il copia-incolla

Preferirei un metodo Windows o alcuni software che potrebbero farlo

Grazie!


4
Come fai a sapere che sono gli stessi file in termini di contenuto? Non riesco a immaginare uno scenario in cui vorresti considerare ciecamente un file come duplicato solo in base al solo nome del file.
rory.ap,

@roryap Penso che questa domanda sia nata perché OP ha copiato i file dalla cartella 1 alla cartella 2, ha sostituito tutto e ora pensa, hmm, questo è stato un errore, ma si rende conto che il giorno successivo, quindi non è possibile annullare. Ma hai ragione, contentwize che non puoi sapere.
LPChip,

13
Solo una domanda stupida ... Perché non usare "taglia" e "incolla"?
DaMachk,

@DaMachk se lavori con unità di rete o supporti rimovibili, copia-> verifica-> la pulizia è un percorso ragionevole. Se i file vengono utilizzati da qualche processo, potrebbe essere una buona idea testarlo su una copia (lo faccio con i file per l'analisi dei dati Python in caso di bug nel mio codice che ostruiscono il file di input (ad esempio). non è più necessario come una volta, ma vecchie abitudini e tutto il resto. In alternativa, l'OP avrebbe potuto fare una copia sbagliata invece di tagliarla,
Chris H,

Risposte:


35

Esiste un software gratuito là fuori chiamato WinMerge . È possibile utilizzare questo software per abbinare i duplicati. Innanzitutto, usa FileOpene scegli entrambe le directory, con la cartella con i file che vuoi mantenere a sinistra e quelli che non hai a destra. Poi, vai a View, e deselezionare Show Different Items, Show Left Unique Itemse Show Right Unique Items. Questo lascerà solo i file identici rimasti nell'elenco. Successivamente, scegli EditSelect All, fai clic con il pulsante destro del mouse su qualsiasi file e fai clic su DeleteRight. Ciò eliminerà i duplicati dalla cartella di destra.

demo di WinMerge


Il vantaggio di questo metodo è che può rilevare se i file non sono simili dal punto di vista del contenuto, se questo è importante. WinMerge può confrontare tutti i fattori che contano con uno.

25

Questo può essere fatto tramite la riga di comando usando il comando forfiles

Supponiamo che tu abbia posizionato la cartella A c:\temp\Folder Ae la cartella B situatac:\temp\Folder B

Il comando sarebbe quindi:

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

Al termine, nella cartella B verranno rimossi tutti i file presenti nella cartella A. Tenere presente che se la cartella B ha file con lo stesso nome, ma non con lo stesso contenuto, verranno comunque eliminati.

È possibile estenderlo per lavorare anche con le cartelle nelle sottocartelle, ma per paura che ciò diventi inutile complicato, ho deciso di non pubblicarlo. Richiederebbe le opzioni / se @relpath (e ulteriori test xD)


11

È possibile utilizzare questo script di 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}
}

Spero che sia abbastanza autoesplicativo. Esamina ogni elemento nella cartella B, controlla se esiste un elemento con lo stesso nome nella cartella A e, in tal caso, rimuove l'elemento della cartella A. Si noti che la finale \nei percorsi delle cartelle è importante.

Versione a una riga:

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

Se non ti interessa se si verifica un diluvio di errori rossi nella console, puoi rimuovere il file -EA 'SilentlyContinue'.

Salvalo come .ps1file, ad es dedupe.ps1. Prima di poter eseguire gli script di PowerShell, devi abilitarne l'esecuzione:

Set-ExecutionPolicy Unrestricted -Scope CurrentUser

Quindi sarai in grado di invocarlo .\dedupe.ps1quando ti trovi nella cartella che lo contiene.


4

rsync

rsyncè un programma utilizzato per sincronizzare la directory. Dai molti (veramente molti) opzioni che avete ci sono il sé che spiega --ignore-non-existing, --remove-source-filese --recursive.

Tu puoi fare

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

se supponiamo che tu abbia i file nella directory A (4) e 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

La risposta di LPChip è la migliore.

Ma poiché ho iniziato ad imparare Python, ho pensato: "Diamine, perché non scrivere uno script Python come risposta a questa domanda?"

Installa Python e Send2Trash

Dovresti installare Python prima di poter eseguire lo script dalla riga di comando.

Quindi installa Send2Trash in modo che i file eliminati non siano andati irrimediabilmente ma finiscano nel cestino del sistema operativo:

pip install Send2Trash

Crea script

Crea un nuovo file con ad esempio il nome DeleteDuplicateInFolderA.py

Copia il seguente script nel file.

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

uso

Modalità di esecuzione a secco, che mostra quali file verrebbero eliminati senza eliminare effettivamente alcun file:

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

Modalità di eliminazione dei file, che effettivamente elimina i file, quindi fai attenzione:

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

Uscita della modalità di funzionamento a secco

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

Uscita della modalità di eliminazione dei file

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 unitario

Se vuoi testare l'applicazione sopra, crea un file chiamato DeleteDuplicateInFolderATest.pye incolla questi unittest in esso:

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

Puoi dirmi perché questa sceneggiatura è "brutta da morire"? L'ho appena letto e quello che stai facendo è cristallino. Sono quasi tentato di incollarlo su CodeReview.SE per conoscere ciò che non è preferito al riguardo.
user1717828,

L'aggiunta di un md5sum per verificare se il contenuto dei file è lo stesso sarebbe una buona opzione. Utilizza anche il meccanismo di cestino del sistema operativo anziché rimuoverlo.
Lolesque,

@ user1717828: ho ristrutturato il codice, ho eliminato quel commento e ho ricevuto il tuo suggerimento di pubblicare il codice su CodeReview.SE .
Lernkurve,

@lolesque: parte Send2Trash: terminata. Grazie per l'idea!
Lernkurve,

1
@barlop, stavo rispondendo al post originale, non a un commento.
user1717828,

1

Usando bash

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

Sicuramente potresti essere più sicuro controllando se il file è presente o controllando se il nome file è sicuro. Ma supponendo che tu voglia solo farlo e non ci siano file ridicolmente nominati, folderBquesto è un modo rapido e sporco per farlo. (e puoi usare l'emulatore bash fornito con git , se non usi Win10 + bash)


Forse devi aggiungere un segno di spunta se trovi le directory ...
Hastur,

1

Qualsiasi programma in stile NC, come Total Commander, ha un comando di differenza di directory che seleziona i file in entrambe le schede che sono diversi dall'altra scheda. Chiamare questo comando, tabnella directory più grande (B), invertire la selezione usando *ed eliminare. Ciò ha il vantaggio di non eliminare i file che potrebbero essere cambiati (in qualche modo) e non sono gli stessi sebbene siano d'accordo nel nome. È possibile utilizzare lo stesso comando diff directory per individuarli dopo l'eliminazione.

Immagino di essere bloccato negli anni novanta ... ma da allora non ho visto nulla di più elegante :-) Finora questa è l'unica risposta che richiede solo 5 sequenze di tasti e nessuna script / riga di comando.


1

Supponiamo che copio e incolli i file dalla cartella A alla cartella B.

C'è un modo per eliminare tutti i file dalla cartella A che si trovano nella cartella B? Oltre a selezionare manualmente ciascuno di essi e cancellarlo, o ctrl-Z'ing subito dopo il copia-incolla

Metodo Windows

Se è sempre necessario copiare i file da una posizione in un'altra e in seguito assicurarsi che anche i file che sono stati copiati correttamente vengano eliminati dalla posizione di origine originale, di seguito è riportata una soluzione di script batch che è possibile utilizzare per automatizzare l'intera attività con un solo basta fare clic su ogni corsa.

  • Assicurati di impostare SourceDirle DestDirvariabili e di conseguenza per le tue esigenze.

  • Inoltre, nella parte dello script seguente ("%SourceDir%\*.*") DOpuoi semplicemente cambiare il *.*valore per renderlo più esplicito per i nomi dei file ( File A.txt) o le estensioni dei file ( *.wav), se necessario.


@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

Ulteriori risorse

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.