比较两个目录中的部分文件名

比较两个目录中的部分文件名

我有两个目录,分别称为 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 的方法读取目录内容一次,解析文本数据并在最后删除文件似乎不错。但是,该答案似乎没有承认两个目录中文件名之间的差异(blurvs. 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

如果有效,请消除回声。但请先进行测试。

相关内容