在所有文件夹和子文件夹中查找重复的不区分大小写的文件名

在所有文件夹和子文件夹中查找重复的不区分大小写的文件名

我有大约 250,000 个文件,它们分布在几个带有子文件夹的文件夹中。正在寻找解决方案,如何在所有文件夹及其子文件夹中查找重复的文件名。我的操作系统是 Ubuntu 22.04,使用bash

我更喜欢bash命令/脚本解决方案。但是,也欢迎提出类似的工具建议fdupes -r(但检查文件名是否相同,而不是检查其内容)。

关于文件及其名称:

  • 所有文件都是图像并具有文件扩展名。
  • 文件的内容并不重要并且可能会有所不同。
  • 文件的扩展名并不重要并且可能不同。
  • 文件名和扩展名的字母大小写不一致。
  • .有些文件的文件名中有多个句点。例如:file_Name2.1.png
  • 文件扩展名由 3 或 4 个符号组成。例如:.png, .JPG,.jpeg

结构:

目录结构非常简单:./[YEAR]/[MONTH]/[IMAGE_NAME].[EXTENSION]。例如:

tree -a
.
├── 2022
│   └── 12
│       ├── file1.png
│       └── File2.png
└── 2023
    ├── 01
    │   ├── file1.jpg
    │   ├── file3.png
    │   └── file4.png
    └── 02
        ├── FILE1.png
        ├── FILE4.PNG
        ├── File5.png
        └── File6.png

预期结果:

  • file1

    ./2022/12/file1.png
    ./2023/01/file1.jpg
    ./2023/02/FILE1.png
    
  • file4

    ./2023/01/file4.png
    ./2023/02/FILE4.PNG
    

答案1

假设您的路径:

  • 没有换行符
  • 文件名中只有一个句点

您可以使用类似如下的方法:

find . -type f | awk -F / '{
  fname = tolower($NF); # Get the filename in lowercase
  sub(/\.[^.]*$/, "", fname); # Strip extension
  paths[fname] = paths[fname] "\n" $0; # Append full path to existing list of filenames separated by newline
  count[fname]++;
} END {
  for (fname in paths)
    if (count[fname] > 1)
      print fname paths[fname] "\n"
}'

答案2

你要求一个 Bash 解决方案,因此@muru 的回答非常棒,但这里有一个 Python 脚本可能会引起您或其他用户的兴趣。

#!/usr/bin/env python
import os
from glob import iglob
import sys

# some simple checks
if len(sys.argv) < 2:
    sys.exit("Path is required.")
elif len(sys.argv) > 2:
    sys.exit("Too many arguments.")
else:
    path = sys.argv[1]

# add files to list recursively
files = [i for i in iglob(path + "/**", recursive=True) if os.path.isfile(i)]
# make list with case-insensitive filenames (all lower)
ifnames = [os.path.splitext(os.path.basename(f))[0].lower() for f in files]

# create a dictionary with case-insensitive filenames as keys and their indexes
# as values
d = {}
for i, f in enumerate(ifnames):
    if f in d:
        d[f].append(i)
    else:
        d[f] = [i]

# print the full paths of the duplicate files grouped by case-insensitive
# filenames
for k, v in d.items():
    if len(v) > 1:
        print()
        print(k)
        for i in v:
            print(files[i])

使用您选择的名称保存脚本后(这里我将使用script.py),运行以下命令赋予其执行权限(将路径替换为实际路径):

chmod u+x /path/to/script.py

该脚本接受一个参数,即您想要在其中查找重复项的目录(目标目录)的路径,如果提供的参数更多或更少,则会引发错误。

您可以按如下方式运行该脚本:

/path/to/script.py /path/to/target/directory

对于您的示例树结构,脚本将返回:

file1
/path/to/target/directory/2022/12/file1.png
/path/to/target/directory/2023/01/file1.jpg
/path/to/target/directory/2023/02/FILE1.png

file4
/path/to/target/directory/2023/01/file4.png
/path/to/target/directory/2023/02/FILE4.PNG

您也可以使用相对路径。例如,运行:

/path/to/script.py .

将在当前目录中搜索重复项,并且如果它是目标目录,则将返回:

file1
./2022/12/file1.png
./2023/01/file1.jpg
./2023/02/FILE1.png

file4
./2023/01/file4.png
./2023/02/FILE4.PNG

相关内容