我有两个目录,分别称为 Directory1 和 Directory2。它们都包含带有一些数字和字符串的图像。Directory1 包含带有数字和 _blur 字符串的模糊图像,例如 001_blur.png。它包含大约 62k 张图像。Directory2 包含相应的精细图像,例如 001_fine.png。它包含 60k 张图像。
问题是我丢失了 Directory1 中的一些模糊图像,而这些图像在 Directory2 中有对应的精细图像对。我也丢失了 Directory2 中的一些精细图像,而这些图像在 Directory1 中有对应的模糊图像。
现在我想只保存具有对应配对的图像。我的意思是,如果其中一个对应图像不存在,我想删除它们,只保存具有配对的图像。
所以我的目录格式是:
Directory1
001_blur.png
002_blur.png
003_blur.png
004_blur.png
Directory2
001_fine.png
002_fine.png
003_fine.png
005_fine.png
注意:我想保留 001 对、002 对和 003 对。我想将模糊复制到 Directory3,将精细复制到 Directory4。
我认为这个问题也有一定的算法复杂性,因为每个文件夹中的图像大约为 60k。如果我从 Directory1 中取出一张图像并尝试在 Directory2 中搜索相应的精细图像,我认为复杂性很高。那么我该如何处理这个算法复杂性呢?
答案1
allo 的方法读取目录内容一次,解析文本数据并在最后删除文件似乎不错。但是,该答案似乎没有承认两个目录中文件名之间的差异(blur
vs. fine
)。
您的文件是根据模式命名的,因此它们的名称不应包含令人讨厌的意外内容,例如不可打印的字符、换行符等。解析ls
应该是安全的,但一般来说不应该这样做。我想给出一个通用的解决方案,所以我不会在这里进行解析。我将使用以空字符结尾的字符串,因此到处都使用像和 这样ls
的开关。-print0
-z
让我们开始吧。您只需要调整变量声明中的路径,除非您复制到另一个文件系统。如果是这样,您还应该调整cp -l
。先阅读评论。我建议您将整个代码块粘贴到文件中,进行调整,然后获取或执行它。
#/bin/bash
# Declare variables.
dir1="/your/directory1/"
dir2="/your/directory2/"
dir3="/your/new/directory3/" # Use absolute paths at least for dir3...
dir4="/your/new/directory4/" # and dir4.
core1=blur
core2=fine
# Create temporary file.
tmpf=$(mktemp)
# Get null-terminated local paths from dir1.
# Note the line doesn't end yet thanks to \.
{ (cd "$dir1"; find -maxdepth 1 -type f -iname "*${core1}*" -print0) ; \
# Add null-terminated local paths from dir2
# (the line continues because of the trailing |)
(cd "$dir2"; find -maxdepth 1 -type f -iname "*${core2}*" -print0) |
# but convert core2 to core1, so the names are all with core1.
# Note the output of the two finds is gathered by {} and piped...
sed -z "s|${core2}|${core1}|" ; } |
# ...to sort and uniq. With uinq -d we print only duplicates, only once.
sort -z | uniq -zd > "$tmpf"
# Note how long this one line was.
# At this moment tmpf lists all the files we need to copy to dir3.
# The filenames are local to dir1, so we have to cd temporarily.
# dir3 will be resolved from dir1, that's why I told to use absolute paths.
# I assume the same filesystem. Creating hardlinks instead of copying;
# remove -l option to do regular copy. Hardlinking.
(cd "$dir1"; xargs -0 -a "$tmpf" cp -alt "$dir3")
# Convert core1 to core2 in tmpf in place.
sed -zi "s|${core1}|${core2}|" "$tmpf"
# Hardlinking from dir2 to dir4.
(cd "$dir2"; xargs -0 -a "$tmpf" cp -alt "$dir4")
# Remove the temporary file.
rm "$tmpf"
答案2
您可以使用以下循环将所有内容放入 Directory3 中,然后删除 Directory1 和 Directory2:
mkdir Directory3
cd Directory1
for file in *
do
# note that the second "cp" is only executed if the first one succeeds:
cp ../Directory2/${file/blur/fine} ../Directory3/ 2>/dev/null && cp $file ../Directory3/
done
cd ..
#rm -rf Directory1 Directory2
答案3
要删除_blur
没有相应“_fine|”的图像:
for f in Dir1/*blur.png;do [[ -f Dir2/$(basename $f _blur.png)_fine.png ]] || echo rm $f;done
按照上述方法尝试一次,然后,如果它似乎做了正确的事情,则删除echo
以实际删除文件。
_fine
删除没有对应的命令_blur
留给读者作为练习。
答案4
您可以创建两个已排序的目录列表并进行比较。
# create the listings
cd Directory1;ls|sed 's/_blur\.png//' >../list1.txt;cd ..
cd Directory2;ls|sed 's/_fine\.png//' >../list2.txt;cd ..
# sort the items, then deduplicate them (uniq) and add the count (-c)
cat list1.txt list2.txt|sort|uniq -c >counts.txt
这将为你提供以 1 或 2 开头的文件名列表。然后你可以执行
# for each line which starts with a 1, remove the 1 and use it as filename
for file in $(grep '^1' counts.txt|sed 's/^1 //');do
# delete it from first or second directory
test -f "Directory1/${file}_blur.png" && echo rm "Directory1/${file}_blur.png"
test -f "Directory2/${file}_fine.png" && echo rm "Directory2/${file}_fine.png"
done
如果有效,请消除回声。但请先进行测试。