同じファイルをハードリンクに変換

同じファイルをハードリンクに変換

私は品質上の理由で、元の購入形式に関係なく、ディレクトリの下のツリーに多くの音楽を保持します。同様の構造を持つ2番目のディレクトリツリーがありますが、すべてのファイルは損失圧縮されているため、携帯電話で再生でき、メタデータが時々変わります(スペースを節約するために埋め込まれたカバーを削除するなど)。

私は音楽のかなりの部分について、2つのケースの間に違いはないことがわかりました。通常、配布バージョンはmp3 / ogg形式でのみ提供され、挿入されたカバーアートがない場合です。ハードドライブのスペースは安いかもしれませんが、それでも無駄にする理由はありません。スクリプトを書く方法はありますか?

  1. 両方のディレクトリに同じファイルがあることを確認する
  2. 同じファイルが見つかるたびに、あるファイルを別のファイルへのハードリンクに置き換えます。
  3. たとえば、時間を節約するために全体の違いを特定するのに時間を費やす必要はありません。
  4. しかし、2つの異なるファイルのコピーを誤って削除するリスクはまだありません。ハッシュだけを比較すると、これはリモートですが、可能性がゼロではありません。

ベストアンサー1

次のコマンドは、md5現在のディレクトリまたは次のディレクトリ内のすべてのファイルのMD5ダイジェストを生成するために使用されます。

find . -type f -exec md5 {} +

BSDユーティリティがない場合は交換してくださいmd5md5sum --tagmd5

ディレクトリでこれを行う簡単なスクリプトを作成しましょう。

#!/bin/bash

tmpdir=${TMPDIR:-/tmp}

if (( $# != 2 )); then
    echo 'Expected two directories as arguments' >&2
    exit 1
fi

i=0
for dir in "$@"; do
    (( ++i ))
    find "$dir" -type f -exec md5 {} + | sort -t '=' -k2 -o "$tmpdir/md5.$i"
done

これは、コマンドラインで2つのディレクトリを使用して、そのディレクトリ内の(または指す場所)ディレクトリごとに1つずつ、md5.1andというファイルを生成します。ファイルはMD5ダイジェストでソートされます。md5.2/tmp$TMPDIR

このファイルは次のとおりです。

MD5 (<path>) = <MD5 digest>

すべてのファイルには次の行があります。

次に、同じスクリプトで2つのファイル間のチェックサムを比較します。

join -t '=' -1 2 -2 2 "$tmpdir"/md5.[12]

これは、チェックサムを結合フィールドとして使用して、2つのファイル間のリレーショナル「結合」操作を実行します。両方のフィールドで同じチェックサム行をマージして出力します。

両方のファイルのチェックサムが同じ場合は、次のように出力されます。

<space><MD5 digest>=MD5 (<path1>) =MD5 (<path2>)

これを直接渡すことで、awk両方のパスを解決できます。

awk -F '[()]' 'BEGIN { OFS="\t" } { print $2, $4 }'

これは、各行をおよびに基づいてフィールド-F [()]に分割したいと言う方法です。これにより、フィールド2と4のパスが残ります。()

これは出力されます

<path1><tab><path2>

次に、タブで区切られたパスのペアを読み、正しいコマンドを実行してリンクを作成します。

while IFS=$'\t' read -r path1 path2; do
    echo ln -f "$path1" "$path2"
done

簡単に言うと:

#!/bin/bash

tmpdir=${TMPDIR:-/tmp}

if (( $# != 2 )); then
    echo 'Expected two directories as arguments' >&2
    exit 1
fi

i=0
for dir in "$@"; do
    (( ++i ))
    find "$dir" -type f -exec md5 {} + | sort -t '=' -k2 -o "$tmpdir/md5.$i"
done

join -t '=' -1 2 -2 2 "$tmpdir"/md5.[12] |
awk -F '\\)|\\(' 'BEGIN { OFS="\t" } { print $2, $4 }' |
while IFS=$'\t' read -r path1 path2; do
    echo ln -f "$path1" "$path2"
done

rm -f "$tmpdir"/md5.[12]

安全のためループechoにありますwhile。一度実行し、何が起こっているのかを確認し、正しいことをしていると確信している場合は、削除してやり直してください。

ハードリンクはパーティションにまたがることができないことを覚えておいてください。これは、両方のディレクトリが同じパーティションにあることを意味します。ファイルは次の場所にあります。第二重複したエントリが見つかったら、ディレクトリを上書きします。結果に満足するまで、元のバックアップをどこかに保管してください。

ファイル名にタブ文字を含むファイルが含まれていると、(このソリューションは正しく機能しません。)

おすすめ記事