V poslední době musím smazat spoustu duplikátů. Sloučím tři nebo čtyři souborové systémy a chci, aby byl prostor využit ekonomicky. Zpočátku se fdupes
zdálo, že je to nejlepší nástroj pro danou práci, ale stále více narážím na omezení.
Zvažte příkaz fdupes -rdN somedirectory/
. Tím se vytvoří hash všech souborů v podadresářích nějakého adresáře.
A když narazí na duplikáty, odstraní je, takže je k dispozici pouze jedna kopie všeho.
Ale co když si chci ponechat somedirectory/subdirectory1/somefile
a ve skutečnosti existují čtyři duplikáty a program nejprve narazí na jeden z duplikátů? Pak odstraní somedirectory/subdirectory1/somefile
, které nechci.
Chci být schopen určit, jaké duplikáty zachovat. A zatím žádný Zdá se, že standardní programy pro práci s duplikáty (duff, FSLint) umožňují automatizaci tohoto druhu chování. Raději nebudu házet svým vlastním, proto se ptám na tuto otázku.
Rád bych mohl psát něco jako
killdupes -rdN --keep=filesin,somedirectories,separated,by,commas somedirectory/
Komentáře
- Byl jsem hledám stejnou věc a našel jsem tuto superuser.com/a/561207/218922
odpověď
I když hledaná funkce není na skladě k dispozici fdupes
, rozdvojil jsem fdupes
(moje vidlice se jmenuje jdupes
) a přidal několik funkcí, které za určitých okolností mohou tento problém vyřešit. příklad v uvedeném případě, kdy si chcete ponechat somedirectory/subdirectory1/somefile
při automatickém mazání duplikátů (d
a N
se přepíná) a pod somedirectory
, jdupes
lze každou cestu podadresáře napájet jako první subdirectory1
a -O
přepínač (který nejprve seřadí soubory podle pořadí parametrů příkazového řádku):
jdupes -nrdNO somedirectory/subdirectory1 somedirectory/subdirectory2 somedirectory/subdirectory3
Toto automaticky smaže všechny soubory kromě jednoho v duplicitní sadě a zaručí, že pokud sada obsahuje soubor v somedirectory/subdirectory1
, bude to první, čímž se automaticky stane zachovaným souborem v sadě . Stále existují do očí bijící limity tohoto přístupu, například skutečnost, že může být zachován jiný duplikát v somedirectory/subdirectory1
místo toho, který jste si chtěli ponechat, ale v mnoha případech, jako je váš, jdupes
možnost pořadí parametrů jako alternativní řešení je dostatečně dobrá.
V blízké budoucnosti plánuji přidat do které umožní obrovské množství kontroly nad zahrnutím / vyloučením souborů, uchováním -N
akcí a aplikací těchto „filtrů“ na globální nebo na -parametrický základ. Tato funkce je velmi nutná; Představuji si něco takového pro „automatické mazání nenulových duplikátů rekurzivně, ALE vždy zachovat somedirectory/subdirectory1/somefile
tak, jak je“:
jdupes -nrdN --filter=preserve:somedirectory/subdirectory1/somefile somedirectory/
Odpověď
Neviděl jsem to nikde jinde: Řekněte, co chcete, toto. Máte / mnt / folder-tree-1 / mnt / folder-tree-2. Nechcete odstranit všechny dupe, ale pokud existuje soubor ve stromu-2 a stejný soubor existuje ve stromu-1 s přesně stejným cesta a název, odstraňte jej ze stromu-2.
Varování: je to docela stručné a pokud se pokusíte kopírovat a vložit toto s omezenými znalostmi prostředí, buďte opatrní.
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
Nebo vše na jednom řádku:
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
Poté zkontrolujte a proveďte rm-v2-dupes.sh
Odpověď
Co takhle pevné propojení duplicitních souborů? Tímto způsobem je prostor použit pouze jednou, ale stále existují ve všech cestách. Háček v tom je, že soubory s pevným odkazem by měly být upraveny na místě (měly by být upraveny pouze odstraněním souboru a jeho opětovným vytvořením s novým obsahem). Druhým přístupem je symbolické propojení souborů dohromady, i když máte stejný problém s rozhodováním o tom, který „primární“ soubor je. To lze provést pomocí následujícího skriptu (i když si uvědomte, že to nezpracovává názvy souborů obsahující mezery).
fdupes --quiet --recurse --sameline somedirectory/ | while read SOURCE DESTS; do for DEST in $DESTS; do ln -f $SOURCE $DEST done done
Komentáře
- Použití
jdupes
namístofdupes
můžete jednoduše přejítjdupes -nrL somedirectory/
, což je výrazně rychlejší. - Překlep v odkazu na jdupes. Odkaz na pohodlí: github.com/jbruchon/jdupes
Odpověď
Měl jsem stejnou otázku.Pokud máte mnoho duplikátů, fdupes /my/directory/ -rdN
uchová soubor s nejstarším datem úpravy, nebo pokud má několik souborů stejné datum úpravy, bude ten nalezen jako první.
Pokud pro vás datum úpravy není důležité, můžete touch
soubory v adresáři, který si chcete ponechat. Pokud je zvolíte touch
s aktuálním datem a časem, fdupes -rdNi
zachová ty s aktuálním datem. Nebo můžete touch
uchovat soubory s datem dřívějším než ty, které chcete smazat, a použít fdupes -rdN
jako obvykle.
Pokud si chcete ponechat datum úpravy, budete muset použít některou z dalších metod.
Odpovědět
Stačí přidat twist k předchozí odpovědi. Následující kód jsem použil několikrát, přičemž jsem mírně upravil předchozí odpověď jednoduchým | grep
k izolaci složky, ze které chci smazat.
`fdupes -r -n -S /directory | grep /delete-from-directory | sed -r "s/^/rm \"/" | sed -r "s/$/\"/" >remove-duplicate-files.sh`
Opět se vytvoří soubor sh, který odstraní všechny uvedené soubory, žádné řádky bez komentářů. Samozřejmě stále můžete soubor upravit tak, aby komentoval konkrétní řádky / soubory, které si chcete ponechat.
Další radou pro velké adresáře je spustit fdupes do souboru txt a poté experimentovat s | grep
a | sed
, dokud nedostanu výsledek chci.
`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`
odpověď
Pomocí sed
vytvořte soubor prostředí, který bude obsahovat komentované příkazy k odstranění každého z vašich duplicitní soubory:
fdupes -r -n -S /directory | sed -r "s/^/#rm \"/" | sed -r "s/$/\"/" >remove-duplicate-files.sh
Výsledný remove-duplicate-files.sh
fil To, co jsme právě vytvořili, bude mít každý řádek komentovaný. Odkomentujte soubory, které chcete smazat. Poté spusťte sh remove-duplicate-files.sh
. Voila!
AKTUALIZACE
Pokud nechcete mazat soubory pouze v určitých adresářích, je to tak jednoduché :
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
Kde exclude_duplicates.py
je:
#/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)
Výsledný remove-duplicate-files-keep-protected.sh
, který jsme právě vytvořili, bude mít všechny soubory z chráněných adresářů komentovány. Otevřete tento soubor ve svém oblíbeném textovém editoru, zkontrolujte, zda je vše v pořádku. Potom jej spusťte. Voila (sic)!
Komentáře
- myslel jsem na to, ale ‚ to není dostatečně automatizované. Hloupě, touto metodou jsem způsobil ztrátu dat, když zacházení s duplikáty rozmístěnými napříč více souborovými systémy … neexistuje ‚ způsob přiřazení priority vzhledem k výstupu fdup es. v zásadě bych musel ručně procházet 10 000 souborů, abych zabránil této ztrátě dat … takže žádné poděkování … ve skutečnosti je právě tato ztráta dat důvodem, proč jsem položil tuto otázku.
- @ixtmixilix, manuální metoda závisí na pozornosti uživatele, zde ‚ není nic nového. Pokud chcete něco automatizovanějšího, podívejte se na aktualizovanou odpověď výše.
Odpověď
A co něco takového?
#!/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
Odpověď
Od Apple Filesystem (APFS), dalšího řešení je uchovat soubory, deduplikovat je a mít žádný vliv na použití disku. Viz Nahradit existující duplicitní soubory na APFS klony