我这里有一个非常困难的问题。
我有一个照片库,其中的各个文件夹中有很多照片。
然后我开始使用 Google Photos 来拍摄我的照片,我将这些原件放入 Google Photos 中,并使用了 5 年多。
现在我想放弃 Google Photos。我已经对我的所有照片进行了 Google 导出,并下载了所有 Zip 文件,其中价值约 1.5TB(150 x 约 10GB 文件)。
现在我想保留原来的目录结构,并删除 Google Photos 中所有重复的文件。在此操作之后,我基本上希望留下两个目录,每个目录中都包含唯一的文件。然后我可以稍后手动合并它。
我已经开始提取所有文件,然后我将运行rmlint
以检测重复项并从 Google Drive 中清除。问题是我没有足够的空间来操作所有这些,所以我必须提取 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
(假设存档路径和成员都不包含换行符或:
字符)获取每个存档的列表<checksum>:<archive>:<file-in-archive>
(需要一段时间,因为sha1sum
每个图像运行一个)。
然后,您可以为每个唯一的校验和仅提取一个文件,如下所示:
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))}++);
}
}'
)
(警告:这一切都未经测试)。