
最近、重複したものを大量に削除する必要が生じました。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/
答え1
あなたが求めている機能は在庫にありませんがfdupes
、私はフォークしましたfdupes
(私のフォークは と呼ばれていますjdupes
)特定の状況下でこの問題を解決できる機能をいくつか追加しました。たとえば、somedirectory/subdirectory1/somefile
重複を自動削除するときに を保持したい場合 (d
とN
スイッチを一緒に使用) で、 の直下に個別のファイルがない場合somedirectory
、各直下のサブディレクトリ パスにfirst とスイッチ (最初にコマンドライン パラメータの順序でファイルを並べ替える) をjdupes
入力できます。subdirectory1
-O
jdupes -rdNO somedirectory/subdirectory1 somedirectory/subdirectory2 somedirectory/subdirectory3
これにより、重複セット内の 1 つのファイルを除くすべてのファイルが自動的に削除され、セットにファイルが含まれている場合はそのファイルがsomedirectory/subdirectory1
最初のファイルになり、自動的にセット内の保存ファイルになります。このアプローチには、somedirectory/subdirectory1
保持したいファイルではなく別の重複ファイルが保存される可能性があるなど、依然として明らかな制限がありますが、多くの場合、jdupes
回避策としてパラメータ順序オプションで十分です。
近い将来、jdupes
ファイルの包含/除外、-N
アクションの保存、およびグローバルまたはパラメータごとの「フィルタ スタック」の適用を詳細に制御できるフィルタリング システムを追加する予定です。この機能は切実に必要です。私は、次のような「ゼロ以外の重複を再帰的に自動削除するが、常にsomedirectory/subdirectory1/somefile
そのまま保存する」機能を思い描いています。
jdupes -rdN --filter=preserve:somedirectory/subdirectory1/somefile somedirectory/
更新 (2022-03-01):2020 年に追加された拡張フィルター オプションを確認してください。-X
これはまさにあなたが望むものではありませんが、nostr
およびonlystr
フィルターを使用すると、フル パス内の無視または必須の部分文字列を指定できます。
答え2
これは他のどこにも見たことがありません。必要なのは次のようなものです。/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を検査して実行します。
答え3
重複ファイルをハードリンクするのはどうでしょうか? そうすれば、スペースは 1 回しか使用されませんが、すべてのパスにスペースが存在します。この場合の注意点は、ハードリンクされたファイルはその場で変更する必要があることです (ファイルを削除して新しいコンテンツで再作成する場合にのみ変更する必要があります)。もう 1 つの方法は、ファイルをシンボリックリンクすることですが、どのファイルが「プライマリ」ファイルであるかを決定するという同じ問題があります。これは、次のスクリプトで実行できます (ただし、スペースを含むファイル名は処理されないことに注意してください)。
fdupes --quiet --recurse --sameline somedirectory/ | while read SOURCE DESTS; do
for DEST in $DESTS; do
ln -f $SOURCE $DEST
done
done
答え4
前回の回答に少し工夫を加えます。前回の回答を少し変更して、| 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`