Recent am nevoie să șterg o mulțime de duplicate. Fuzionez trei sau patru sisteme de fișiere și vreau ca spațiul să fie folosit economic. La început, fdupes mi s-a părut că este cel mai bun instrument pentru sarcină, dar tot mai întâmpin limitări.

Luați în considerare comanda fdupes -rdN somedirectory/. Aceasta face un hash al tuturor fișierelor din subdirectoarele somedirectory.

Și când întâlnește duplicate, le șterge, astfel încât să existe o singură copie a tuturor.

Dar dacă vreau să păstrez somedirectory/subdirectory1/somefile și există, de fapt, patru duplicate, iar programul întâlnește mai întâi unul dintre duplicate? Apoi șterge somedirectory/subdirectory1/somefile, ceea ce nu vreau.

Vreau să pot specifica, cumva, ce duplicate să păstreze. Și până acum, niciuna dintre programele standard pentru tratarea duplicatelor (duff, FSLint) par să permită automatizarea acestui tip de comportament. Aș prefera să nu-mi rulez propriile, așa că de aceea pun această întrebare.

Mi-ar plăcea să pot scrie ceva de genul

killdupes -rdN --keep=filesin,somedirectories,separated,by,commas somedirectory/ 

Comentarii

Răspuns

Deși funcționalitatea pe care o căutați nu este disponibilă în stoc fdupes, am forțat fdupes (furculița mea se numește jdupes) și a adăugat câteva caracteristici care pot rezolva această problemă în anumite circumstanțe. de exemplu, în cazul menționat în care doriți să păstrați somedirectory/subdirectory1/somefile când ștergerea automată a duplicatelor (d și N comută împreună) și nu există fișiere separate imediat sub somedirectory, jdupes poate fi alimentat fiecare cale subdirectorie imediată cu subdirectory1 mai întâi și -O comutator (care sortează mai întâi fișierele după ordinea parametrilor din linia de comandă):

jdupes -nrdNO somedirectory/subdirectory1 somedirectory/subdirectory2 somedirectory/subdirectory3

Aceasta va șterge automat toate fișierele cu excepția unuia dintr-un set duplicat și va garanta că dacă setul conține un fișier în somedirectory/subdirectory1 acesta va fi primul, devenind astfel automat fișierul conservat din set . Există încă limite evidente la această abordare, cum ar fi faptul că un alt duplicat din somedirectory/subdirectory1 ar putea fi păstrat în locul celui pe care ați dorit să îl păstrați, dar într-un număr mare de cazuri ca al vostru, opțiunea de comandă a parametrilor jdupes ca soluție este suficient de bună.

În viitorul apropiat, intenționez să adaug un sistem de filtrare la jdupes care va permite o cantitate imensă de control asupra includerii / excluderii fișierelor, păstrării pentru acțiunile -N și aplicarea unor astfel de „stive de filtrare” fie la nivel global, fie pe -baza parametrului. Această caracteristică este extrem de necesară; Îmi imaginez ceva de genul acesta pentru „ștergerea automată a duplicatelor diferite de zero în mod recursiv DAR să păstrez întotdeauna somedirectory/subdirectory1/somefile așa cum este”:

jdupes -nrdN --filter=preserve:somedirectory/subdirectory1/somefile somedirectory/

Răspuns

Nu l-am văzut nicăieri altundeva: Spune ce vrei este asta. Ai / mnt / folder-tree-1 / mnt / folder-tree-2. Nu doriți să eliminați fiecare dupe, dar dacă există un fișier în tree-2 și un fișier identic există în tree-1 cu exact același cale și nume, eliminați-l din copac-2.

Atenție: este destul de concis și dacă încercați să copiați-lipiți acest lucru cu abilități reduse de shell, aveți grijă.

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 

Sau toate pe o singură linie:

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 

Ulterior, inspectați și executați rm-v2-dupes.sh

Răspuns

Cum rămâne cu legătura solidă a fișierelor duplicate împreună? În acest fel, spațiul este folosit o singură dată, dar ele încă există pe toate căile. Cea mai bună problemă este că fișierele hardlink-uri ar trebui modificate la locul lor (acestea ar trebui modificate doar ștergând fișierul și recreându-l cu noul conținut). Cealaltă abordare este legarea simbolică a fișierelor împreună, deși aveți aceeași problemă de a decide care este fișierul „primar”. Acest lucru se poate face cu următorul script (deși rețineți că acest lucru „nu gestionează numele de fișiere care conțin spații).

fdupes --quiet --recurse --sameline somedirectory/ | while read SOURCE DESTS; do for DEST in $DESTS; do ln -f $SOURCE $DEST done done 

Comentarii

  • Utilizarea jdupes în loc de fdupes pur și simplu puteți accesa jdupes -nrL somedirectory/, care este mult mai rapid.
  • Scrieți în legătura către jdupes. Link de comoditate: github.com/jbruchon/jdupes

Răspuns

Am avut aceeași întrebare.Dacă aveți multe duplicate, fdupes /my/directory/ -rdN păstrează fișierul cu cea mai veche dată de modificare sau dacă mai multe fișiere au aceeași dată de modificare, atunci cea găsită mai întâi.

Dacă data de modificare nu este importantă pentru dvs., puteți touch fișierele din directorul pe care doriți să îl păstrați. Dacă alegeți să touch le cu data și ora curente, atunci fdupes -rdNi le va păstra pe cele cu data curentă. Sau puteți touch păstra fișierele cu o dată anterioară celei pe care doriți să le ștergeți și să utilizați fdupes -rdN în mod normal.

Dacă trebuie să păstrați data modificării, va trebui să utilizați una dintre celelalte metode.

Răspuns

Doar pentru a adăuga o răsucire la un răspuns anterior. Am folosit următorul cod de mai multe ori, modificând ușor un răspuns anterior cu un simplu | grep pentru a izola folderul din care vreau să șterg.

`fdupes -r -n -S /directory | grep /delete-from-directory | sed -r "s/^/rm \"/" | sed -r "s/$/\"/" >remove-duplicate-files.sh` 

Din nou, acest lucru va crea un fișier sh pentru a șterge toate fișierele listate, fără linii comentate. Desigur, puteți edita fișierul pentru a comenta anumite linii / fișiere pe care doriți să le păstrați.

Un alt indiciu pentru directoarele mari este de a rula fdupes într-un fișier txt, apoi experimentați cu | grep și | sed până când obțin rezultat vreau.

`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` 

Răspuns

Utilizați sed pentru a crea un fișier shell care va conține comenzi comentate pentru a șterge fiecare dintre fișiere duplicat:

fdupes -r -n -S /directory | sed -r "s/^/#rm \"/" | sed -r "s/$/\"/" >remove-duplicate-files.sh 

Rezultatul remove-duplicate-files.sh fil Dacă tocmai am creat, vom comenta fiecare linie. Decomentați fișierele pe care doriți să le ștergeți. Apoi rulați sh remove-duplicate-files.sh . Voila!

UPDATE

Ei bine, dacă nu doriți să ștergeți fișiere numai în anumite directoare, este la fel de simplu ca acest :

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 

Unde este exclude_duplicates.py:

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

Rezultatul remove-duplicate-files-keep-protected.sh fișier pe care tocmai l-am creat va avea comentarii toate fișierele din directoarele protejate. Deschideți acest fișier în editorul dvs. de text preferat, verificați dacă totul este în regulă. Apoi rulați-l. Voila (sic)!

Comentarii

  • M-am gândit la asta, dar ‘ nu este suficient de automatizat. În mod stupid, am cauzat pierderea de date cu această metodă când tratarea duplicatelor distanțate pe mai multe sisteme de fișiere … nu există ‘ nicio modalitate de a atribui o prioritate, având în vedere ieșirea fdup es. Practic, ar fi trebuit să traversez manual 10000 de fișiere pentru a preveni pierderea de date … deci, nu, mulțumesc … de fapt, pierderea de date este chiar motivul pentru care am pus această întrebare.
  • @ixtmixilix, ei bine, metoda manuală depinde de atenția utilizatorului, aici ‘ nu este nimic nou. Dacă doriți ceva mai automatizat, verificați un răspuns actualizat de mai sus.

Răspuns

Ce se întâmplă cu așa ceva?

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

Răspuns

În ceea ce privește sistemul de fișiere Apple (APFS), o altă soluție este să păstreze fișierele, să le deduplicăm și să nu avem niciun impact asupra utilizării discului. Consultați Înlocuiți fișierele duplicate existente pe APFS cu clone

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *