ここには非常に難しい問題があります。
さまざまなフォルダに多数の写真を含むフォトライブラリがあります。
それからGoogleフォトを使って写真を撮り始め、そのオリジナルをGoogleフォトに入れて5年以上使っていました。
今Googleフォトを放棄したいと思います。すべての写真をGoogleにエクスポートし、約1.5TB(150 x〜10 GBファイル)相当のすべてのZipファイルをダウンロードしました。
元のディレクトリ構造を維持し、Googleフォトからすべての重複ファイルを削除したいと思います。この操作の後、デフォルトでは、それぞれに一意のファイルを含む2つのディレクトリが残ります。その後、後で手動でマージできます。
rmlint
重複したアイテムを検出し、Googleドライブから削除するために実行するすべてのファイルの抽出を開始しました。問題は、それをすべて運営するにはスペースが不足しているため、30個のアーカイブを抽出した後に実行し、消去し、rmlint
また30個抽出し、rmlint
再実行して、消去するなどの過程を経なければならないという点です。これは元のファイルを再スキャンし続けるため、完了するのに長い時間がかかります。私は--xattr
その後の実行速度を上げるためにrmlintフラグを使用しました。完全なコマンドrmlint
については付録を参照してください。
まず、すべてのアーカイブを抽出せずにこれを実行できますか? zipファイルのファイルチェックサムを使用してそのファイルと比較する方法はありますか?
ありがとうございます!
付録
rmlint \
--xattr \
-o sh:rmlint-photos.sh \
-o json:rmlint-photos.json \
--progress \
--match-basename \
--keep-all-tagged \
--must-match-tagged \
"/mnt/f/GoogleTakeout/" \
// \
"/mnt/e/My Documents/Pictures/" \
答え1
zsh または bash だけでなく、libarchivebsdtar
と GNU でもtar
次のことができます。
LC_ALL=C find . -name '*.zip' -type f -print0 |
while IFS= read -rd '' archive; do
bsdtar -cf - "@$archive" |
ARCHIVE=$archive tar -xf - --to-command='
case $TAR_FILETYPE$TAR_FILENAME in
(f*.jpg | f*.JPG)
sha1sum | {
IFS= read -r sum rest &&
printf "%s\n" "$sum:$ARCHIVE:$TAR_FILENAME"
}
esac' > sums.txt
(アーカイブパスまたはメンバーに改行や:
文字が含まれていないと仮定)各アーカイブのリストを取得します(画像ごとに1つが実行されるため<checksum>:<archive>:<file-in-archive>
時間がかかります)。sha1sum
その後、次のように各固有チェックサムに対して1つのファイルのみを抽出できます。
perl -F: -slane '
($sum, $archive, $file) = @F;
if (!$seen{$sum}++) {
push @{$files{$archive}}, $file;
}
END {
for $archive (keys %files) {
open EXTRACT, "|-", "bsdtar", "-C", $dest, "-T", "/dev/stdin", "-xvnf", $archive;
for (@{$files{$archive}}) {
s/[][?*\\]/\\$&/g; # escape wildcards
print EXTRACT;
}
}
}' -- -dest='/mnt/e/My Documents/Pictures/' sums.txt
(より多くのエラー処理を追加する必要があるかもしれません)。
perl
しかしながら、同時にチェックサム抽出を実行する方が効率的であり得る。
(LC_ALL=C find "$PWD" -name '*.zip' -type f -print0 | {
cd '/mnt/e/My Documents/Pictures' &&
perl -MArchive::Zip -MDigest::SHA=sha1 -0lne '
my $zip = Archive::Zip->new();
if ($zip->read($_) == AZ_OK) {
for $member ($zip->membersMatching(".*\.jpe?g")) {
$zip->extractMember($member)
unless (!$seen{sha1(zip->contents($member))}++);
}
}'
)
(警告:これはすべてテストされていません)。