web-dev-qa-db-ja.com

fdupes -rdNよりも詳細な重複を削除する方法はありますか?

最近、多くの重複を削除する必要があります。 3つまたは4つのファイルシステムをマージしていますが、スペースを経済的に使用したいと考えています。最初はfdupesがその仕事に最適なツールであるように見えましたが、ますます制限に直面しています。

コマンドfdupes -rdN somedirectory/を考えてみましょう。これにより、somedirectoryのサブディレクトリにあるすべてのファイルのハッシュが作成されます。

また、重複が見つかった場合は削除するため、すべてのコピーが1つだけになります。

しかし、somedirectory/subdirectory1/somefileを保持したいが、実際には4つの重複があり、プログラムが重複の1つを最初に検出した場合はどうなりますか?次に、不要なsomedirectory/subdirectory1/somefileを削除します。

何が重複して保持するかを指定できるようにしたい。そして、これまでのところ、重複を処理するための標準プログラム(duff、FSLint)は、そのような動作の自動化を許可していないようです。自分で転がしたくないので、この質問をします。

私は次のようなものを書けるようになりたいです

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

お求めの機能は在庫fdupesではご利用いただけませんが、fdupes(私のフォークはjdupes をフォークして、特定の状況下でこの問題を解決できるいくつかの機能を追加しました。たとえば、重複を自動削除するときにsomedirectory/subdirectory1/somefileを保持したい(dNスイッチを一緒に)記載したケースで、somedirectoryのすぐ下に個別のファイルがない場合、jdupesには、最初のsubdirectory1-Oスイッチ(コマンドラインパラメーターの順序でファイルを最初に並べ替えます):

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

これにより、重複セット内の1つを除くすべてのファイルが自動的に削除され、セットにsomedirectory/subdirectory1内のファイルが含まれている場合は、それが最初になり、自動的にセット内の保存ファイルになります。この方法には、保持したいものの代わりにsomedirectory/subdirectory1の別の重複が保持される可能性があるなど、依然として明らかな制限がありますが、多くの場合、回避策としてのjdupesパラメータの順序オプションで十分です。

近い将来、フィルタリングシステムをjdupesに追加して、ファイルの包含/除外、-Nアクションの保持、およびグローバルまたはパラメーターごとのそのような「フィルタースタック」の適用を大幅に制御できるようにする予定です。基礎。この機能は非常に必要です。私はこのようなものを「ゼロ以外の重複を再帰的に自動削除するが、常にsomedirectory/subdirectory1/somefileを現状のまま維持する」ことを想定しています。

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

6

私はこれを他のどこにも見ませんでした:あなたが欲しいのはこれだと言ってください。/mnt/folder-tree-1/mnt/folder-tree-2があります。すべての重複を削除するのではなく、tree-2にファイルが存在し、まったく同じパスと名前を持つ同じファイルがtree-1に存在する場合は、tree-2から削除します。

警告:これは非常に簡潔であり、シェルのスキルが限られている場合にこれをコピーして貼り付けようとする場合は注意してください。

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

またはすべて1行で:

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

その後、rm-v2-dupes.shを検査して実行します。

5
Gaute Lund

同じ質問がありました。重複が多い場合fdupes /my/directory/ -rdNは、変更日が最も古いファイルを保持します。または、複数のファイルが同じ変更日を持っている場合は、最初に見つかったファイルです。

変更日が重要でない場合は、保持するディレクトリ内のファイルをtouchできます。現在の日付と時刻でtouchを選択する場合、fdupes -rdNiは現在の日付のものを保持します。または、削除したいファイルよりも古い日付のkeepファイルをtouch使用してfdupes -rdN 普段通り。

変更日を保持する必要がある場合は、他の方法のいずれかを使用する必要があります。

4
pheon

重複ファイルを一緒にハードリンクするのはどうですか?この方法では、スペースは一度しか使用されませんが、それらはすべてのパスにまだ存在しています。これの難点は、ハードリンクされたファイルを適切に変更する必要があることです(ファイルを削除して、新しいコンテンツで再作成する場合にのみ変更する必要があります)。もう1つの方法は、ファイルをシンボリックリンクすることですが、「プライマリ」ファイルを決定するのと同じ問題があります。これは次のスクリプトで実行できます(ただし、これはスペースを含むファイル名を処理しないことに注意してください)。

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

前の答えにひねりを加えるだけです。次のコードを複数回使用して、以前の回答を単純な| grep削除するフォルダを分離します。

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

繰り返しますが、これによりshファイルが作成され、リストされたすべてのファイルが削除されます。コメント行はありません。もちろん、ファイルを編集して、保持したい特定の行/ファイルをコメント化することもできます。

大きなディレクトリのもう1つのヒントは、txtファイルに対してfdupesを実行してから、| grepおよび| sed必要な結果が得られるまで。

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

sed を使用して、重複する各ファイルを削除するコメント化されたコマンドを含むシェルファイルを作成します。

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

作成したremove-duplicate-files.shファイルは、各行がコメント化されています。削除するファイルのコメントを外します。次に、sh remove-duplicate-files.shを実行します。出来上がり!

[〜#〜]更新[〜#〜]

まあ、特定のディレクトリのファイルだけを削除したくない場合は、これは次のように簡単です

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

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)

作成した結果のremove-duplicate-files-keep-protected.shファイルには、保護されたディレクトリのすべてのファイルがコメント化されています。このファイルをお気に入りのテキストエディタで開き、すべて問題ないことを確認します。次に、それを実行します。出来上がり(sic)!

2
Ivan Kharlamov

このようなものはどうですか?

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

Apple Filesystem(APFS))の時点での別の解決策は、ファイルを保持し、重複排除して、ディスクの使用に影響を与えないことです。 クローン を使用したAPFS上の重複ファイル

0
Tim