For nylig har jeg behovet for at slette mange duplikater. Jeg fusionerer tre eller fire filsystemer, og jeg vil have, at pladsen skal bruges økonomisk. Først syntes fdupes
, at det var det bedste værktøj til jobbet, men jeg løber i stigende grad i begrænsninger.
Overvej kommandoen fdupes -rdN somedirectory/
. Dette gør en hash af alle filerne i underkatalogerne i somedirectory.
Og når det støder på dubletter, sletter det dem, så der kun er én kopi af alt.
Men hvad hvis jeg vil beholde somedirectory/subdirectory1/somefile
og der er faktisk fire duplikater, og programmet møder en af duplikaterne først? Derefter sletter den somedirectory/subdirectory1/somefile
, som jeg ikke vil have.
Jeg vil på en eller anden måde være i stand til at specificere, hvilke duplikater der skal holdes. Og indtil videre er der ingen af standardprogrammerne til håndtering af duplikater (duff, FSLint) ser ud til at tillade automatisering af den slags adfærd. Jeg foretrækker ikke at rulle mine egne, så det er derfor, jeg spørger dette spørgsmål.
Jeg vil gerne være i stand til at skrive noget som
killdupes -rdN --keep=filesin,somedirectories,separated,by,commas somedirectory/
Kommentarer
- jeg var på udkig efter det samme, og jeg fandt dette superbruger.com/a/561207/218922
Svar
Mens den funktionalitet, du søger, ikke er tilgængelig på lager fdupes
, gaffede jeg fdupes
(min gaffel hedder jdupes
) og tilføjede nogle funktioner, der kan løse dette problem under visse omstændigheder. eksempel i det angivne tilfælde, hvor du ønsker at beholde somedirectory/subdirectory1/somefile
når automatisk sletning af dubletter (d
og N
skifter sammen), og der er ingen separate filer umiddelbart under somedirectory
, jdupes
kan tilføres hver øjeblikkelige underkatalogsti med subdirectory1
først og -O
switch (der sorterer filer efter kommandolinjeparameterrækkefølge først):
jdupes -nrdNO somedirectory/subdirectory1 somedirectory/subdirectory2 somedirectory/subdirectory3
Dette sletter automatisk alle undtagen en fil i et duplikat sæt og garanterer, at hvis sættet indeholder en fil i somedirectory/subdirectory1
, vil den være den første og derved automatisk blive den bevarede fil i sættet . Der er stadig skarpe grænser for denne tilgang, såsom det faktum, at en anden kopi i somedirectory/subdirectory1
muligvis bevares i stedet for den, du ønskede at beholde, men i et stort antal tilfælde som din, jdupes
parameterordreindstillingen som en løsning er god nok.
I den nærmeste fremtid planlægger jeg at tilføje et filtreringssystem til jdupes
der muliggør en enorm mængde kontrol over inkludering / ekskludering af filer, bevarelse af -N
handlinger og anvendelse af sådanne “filterstakke” på enten en global eller pr. -parameter basis. Denne funktion er meget nødvendig; Jeg forestiller mig noget som dette for “automatisk at slette ikke-nul-duplikater rekursivt MEN altid bevare somedirectory/subdirectory1/somefile
som det er”:
jdupes -nrdN --filter=preserve:somedirectory/subdirectory1/somefile somedirectory/
Svar
Jeg så den ikke andre steder: Sig hvad du vil, er dette. Du har / mnt / folder-tree-1 / mnt / folder-tree-2. Du vil ikke fjerne enhver dupe, men hvis der findes en fil i tree-2, og der findes en identisk fil i tree-1 med nøjagtig samme sti og navn, fjern det fra træ-2.
Advarsel: dette er ganske kort, og hvis du forsøger at kopiere og indsætte dette med begrænsede shell-færdigheder, skal du være forsigtig.
fdupes -rn /mnt/folder-tree-1/ /mnt/folder-tree-2/ > dupes-all.txt fgrep /mnt/folder-tree-1/ dupes-all.txt | while read line do if grep -q "`echo $line | sed -e "s|^/mnt/folder-tree-1/|/mnt/folder-tree-2/|"`" dupes-all.txt then echo rm \"$(echo $line | sed -e "s|^/mnt/folder-tree-1/|/mnt/folder-tree-2//|")\" fi done > rm-v2-dupes.sh
Eller alle på én linje:
fdupes -rn /mnt/folder-tree-1/ /mnt/folder-tree-2/ > dupes-all.txt; fgrep /mnt/folder-tree-1/ dupes-all.txt | while read line; do if grep -q "`echo $line | sed -e "s|^/mnt/folder-tree-1/|/mnt/folder-tree-2/|"`" dupes-all.txt; then echo rm \"$(echo $line | sed -e "s|^/mnt/folder-tree-1/|/mnt/folder-tree-2/|")\"; fi; done > rm-v2-dupes.sh
Bagefter inspicerer og udfører rm-v2-dupes.sh
Svar
Hvad med hardlinkning af de duplikerede filer sammen? På den måde bruges rummet kun én gang, men de findes stadig på alle stier. Fangsten med dette er, at hardlinkede filer skal ændres på plads (de skal kun modificeres ved at slette filen og genskabe den med det nye indhold). Den anden tilgang er at sammenkæde filerne sammen, selvom du har det samme spørgsmål om at beslutte, hvilken “primære” fil der er. Dette kunne gøres med følgende script (dog bemærk, at dette ikke håndterer filnavne, der indeholder mellemrum).
fdupes --quiet --recurse --sameline somedirectory/ | while read SOURCE DESTS; do for DEST in $DESTS; do ln -f $SOURCE $DEST done done
Kommentarer
- Brug af
jdupes
i stedet forfdupes
du kan simpelthen gåjdupes -nrL somedirectory/
hvilket er enormt hurtigere. - Skriv i linket til jdupes. Bekvemmelighedslink: github.com/jbruchon/jdupes
Svar
Jeg havde det samme spørgsmål.Hvis du har mange dubletter fdupes /my/directory/ -rdN
holder filen filen med den ældste ændringsdato, eller hvis flere filer har den samme ændringsdato, er den der blev fundet først.
Hvis ændringsdatoen ikke er vigtig for dig, kan du touch
filerne i det bibliotek, du vil beholde. Hvis du vælger at touch
dem med den aktuelle dato og klokkeslæt, vil fdupes -rdNi
beholde dem med den aktuelle dato. Eller du kan touch
beholde filerne med en dato, der er tidligere end dem, du vil slette, og bruge fdupes -rdN
som normalt.
Hvis du har brug for at holde ændringsdatoen, skal du bruge en af de andre metoder.
Svar
Bare for at tilføje et twist til et tidligere svar. Jeg har brugt følgende kode flere gange og ændret lidt et tidligere svar med en simpel | grep
for at isolere den mappe, jeg vil slette fra.
`fdupes -r -n -S /directory | grep /delete-from-directory | sed -r "s/^/rm \"/" | sed -r "s/$/\"/" >remove-duplicate-files.sh`
Igen opretter dette en sh-fil til at slette alle de anførte filer, ingen kommenterede linjer. Selvfølgelig kan du stadig redigere filen for at kommentere specifikke linjer / filer, du vil beholde.
Et andet tip til store mapper er at køre fdupes til en txt-fil og derefter eksperimentere med | grep
og | sed
indtil jeg får resultat, jeg vil.
`fdupes -r -n -S /directory > duplicate-files.txt` `cat duplicate-files.txt | grep /delete-from-directory | sed -r "s/^/rm \"/" | sed -r "s/$/\"/" >remove-duplicate-files.sh`
Svar
Brug sed
til at oprette en shell-fil, der indeholder kommandoer, der er kommenteret, for at slette hver af dine duplikerede filer:
fdupes -r -n -S /directory | sed -r "s/^/#rm \"/" | sed -r "s/$/\"/" >remove-duplicate-files.sh
Den resulterende remove-duplicate-files.sh
fil e, som vi lige har oprettet, får hver linje kommenteret. Fjern kommentar til de filer, du vil slette. Kør derefter sh remove-duplicate-files.sh
. Voila!
OPDATERING
Hvis du ikke kun vil slette filer i bestemte mapper, er det så simpelt som dette :
fdupes -S /directory|sed "/^$/d" |sed -r "s/^[0-9]/#&/" > duple_list python exclude_duplicates.py -f /path/to/dupe_list --delimiter="#" --keep=/full/path/to/protected/directory1,/full/path/to/protected/directory2\ with\ spaces\ in\ path >remove-duplicate-files-keep-protected.sh
Hvor exclude_duplicates.py
er:
#/usr/bin/python # -*- coding: utf-8 -*- # exclude_duplicates.py """ THE SCRIPT DOESN"T DELETE ANYTHING, IT ONLY GENERATES TEXT OUTPUT. Provided a list of duplicates, such as fdupes or fslint output, generate a bash script that will have all duplicates in protected directories commented out. If none of the protected duplicates are found in a set of the same files, select a random unprotected duplicate for preserving. Each path to a file will be transformed to an `rm "path"` string which will be printed to standard output. """ from optparse import OptionParser parser = OptionParser() parser.add_option("-k", "--keep", dest="keep", help="""List of directories which you want to keep, separated by commas. \ EXAMPLE: exclude_duplicates.py --keep /path/to/directory1,/path/to/directory\ with\ space\ in\ path2""", metavar="keep" ) parser.add_option("-d", "--delimiter", dest="delimiter", help="Delimiter of duplicate file groups", metavar="delimiter" ) parser.add_option("-f", "--file", dest="file", help="List of duplicate file groups, separated by delimiter, for example, fdupes or fslint output.", metavar="file" ) (options, args) = parser.parse_args() directories_to_keep = options.keep.split(",") file = options.file delimiter = options.delimiter pretty_line = "\n#" + "-" * 35 print "#/bin/bash" print "#I will protect files in these directories:\n" for d in directories_to_keep: print "# " + d print pretty_line protected_set = set() group_set = set() def clean_set(group_set, protected_set, delimiter_line): not_protected_set = group_set - protected_set while not_protected_set: if len(not_protected_set) == 1 and len(protected_set) == 0: print "#randomly selected duplicate to keep:\n#rm "%s"" % not_protected_set.pop().strip("\n") else: print "rm "%s"" % not_protected_set.pop().strip("\n") for i in protected_set: print "#excluded file in protected directory:\n#rm "%s"" % i.strip("\n") print "\n#%s" % delimiter_line file = open(file, "r") for line in file.readlines(): if line.startswith(delimiter): clean_set(group_set, protected_set, line) group_set, protected_set = set(), set() else: group_set = group_set|{line} for d in directories_to_keep: if line.startswith(d): protected_set = protected_set|{line} else: if line: clean_set(group_set, protected_set, line)
Den resulterende remove-duplicate-files-keep-protected.sh
-fil, som vi lige har oprettet, får alle filer fra beskyttede mapper kommenteret. Åbn denne fil i din foretrukne teksteditor, kontroller at alt er i orden. Kør den derefter. Voila (sic)!
Kommentarer
- jeg tænkte på dette, men det ‘ er ikke automatiseret nok. Dumt, jeg forårsagede datatab med denne metode, når beskæftiger sig med dubletter fordelt på flere filsystemer … der ‘ er ingen måde at tildele en prioritet på grund af output af fdup es. dybest set ville jeg have været nødt til at trawl gennem 10000 filer i hånden for at forhindre, at datatab … så nej tak … faktisk er datatab netop grunden til, at jeg stillede dette spørgsmål.
- @ixtmixilix, ja, manuel metode er afhængig af brugerens opmærksomhed, her er ‘ intet nyt. Hvis du vil have noget mere automatiseret, skal du tjekke et opdateret svar ovenfor.
Svar
Hvad med noget som dette?
#!/bin/bash DUPE_SEARCH_DIR=somedir/ PREFERRED_DIRS=("somedir/subdir1" "somedir/subdir2") DUPE_FILE=/tmp/`basename $0`_found-duplicates delete_dupes() { while read line ; do if [ -n "$line" ] ; then matched=false for pdir in "${PREFERRED_DIRS[@]}" ; do if [[ $line == $pdir/* ]] ; then matched=true break fi done if ! $matched ; then rm -v "$line" fi fi done < "$DUPE_FILE" } cleanup() { rm -f $DUPE_FILE } trap cleanup EXIT # get rid of normal dupes, preserve first & preserve preferred fdupes -rf "$DUPE_SEARCH_DIR" > $DUPE_FILE delete_dupes # get rid of preserve dupes, preserve preferred fdupes -r "$DUPE_SEARCH_DIR" > "$DUPE_FILE" delete_dupes
Svar
Fra Apple Filesystem (APFS) er en anden løsning er at opbevare filerne, deduplicate dem og ikke have nogen indvirkning på diskbrug. Se Erstat eksisterende duplikatfiler på APFS med kloner