最近、多くの重複を削除する必要があります。 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/
お求めの機能は在庫fdupes
ではご利用いただけませんが、fdupes
(私のフォークはjdupes
) をフォークして、特定の状況下でこの問題を解決できるいくつかの機能を追加しました。たとえば、重複を自動削除するときにsomedirectory/subdirectory1/somefile
を保持したい(d
とN
スイッチを一緒に)記載したケースで、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/
私はこれを他のどこにも見ませんでした:あなたが欲しいのはこれだと言ってください。/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を検査して実行します。
同じ質問がありました。重複が多い場合fdupes /my/directory/ -rdN
は、変更日が最も古いファイルを保持します。または、複数のファイルが同じ変更日を持っている場合は、最初に見つかったファイルです。
変更日が重要でない場合は、保持するディレクトリ内のファイルをtouch
できます。現在の日付と時刻でtouch
を選択する場合、fdupes -rdNi
は現在の日付のものを保持します。または、削除したいファイルよりも古い日付のkeepファイルをtouch
使用してfdupes -rdN
普段通り。
変更日を保持する必要がある場合は、他の方法のいずれかを使用する必要があります。
重複ファイルを一緒にハードリンクするのはどうですか?この方法では、スペースは一度しか使用されませんが、それらはすべてのパスにまだ存在しています。これの難点は、ハードリンクされたファイルを適切に変更する必要があることです(ファイルを削除して、新しいコンテンツで再作成する場合にのみ変更する必要があります)。もう1つの方法は、ファイルをシンボリックリンクすることですが、「プライマリ」ファイルを決定するのと同じ問題があります。これは次のスクリプトで実行できます(ただし、これはスペースを含むファイル名を処理しないことに注意してください)。
fdupes --quiet --recurse --sameline somedirectory/ | while read SOURCE DESTS; do
for DEST in $DESTS; do
ln -f $SOURCE $DEST
done
done
前の答えにひねりを加えるだけです。次のコードを複数回使用して、以前の回答を単純な| 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`
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)!
このようなものはどうですか?
#!/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
Apple Filesystem(APFS))の時点での別の解決策は、ファイルを保持し、重複排除して、ディスクの使用に影響を与えないことです。 クローン を使用したAPFS上の重複ファイル