根据文件名的前几个字符查找重复文件

根据文件名的前几个字符查找重复文件

我正在 Linux shell 中寻找一种方法,最好是 bash 来根据文件名的前几个字母查找文件的重复项。

这会有用的地方:

我为 Minecraft 构建模组包。从 1.14.4 开始,如果更高版本包中存在重复的 mod,Forge 不再出错。它只是停止最旧版本的运行。帮助查找这些重复项的脚本将非常有利。

清单示例:

minecolonies-0.13.312-beta-universal.jar   
minecolonies-0.13.386-alpha-universal.jar 

通过快速识别受骗者,我可以保持较小的客户群。

根据要求提供更多信息

没有特定的格式。然而,正如您所看到的,至少有两种流行的格式。此外,社区中没有关于使用或不使用哪种字符的标准。有些使用空格(更恶心),有些使用 [](也很恶心),有些使用 _(更恶心),有些使用 -(首选,但你能做什么)。

https://gist.github.com/be3cc9a77150194476b2000cb8ee16e5示例 mods 文件名列表。已经清理干净,所以里面没有骗人的东西。

https://gist.github.com/b0ac1e03145e893e880da45cf08ebd7a包含一个我故意复制的样本。这是时有发生的过分夸大的事情。

更深入的解释

我意识到这可能会占用大量资源。

我想任意指定要采样的所有文件名的从开始到结束的切片范围。根据该切片查找重复项,然后突出显示重复项。我不需要脚本来实际删除它们。

额外学分

该脚本将为怀疑符合复制标准的文件显示一个菜单,以便轻松删除或重命名。

答案1

过滤可能的重复项

您可以使用一些脚本来过滤这些文件以查找可能的重复项。您可以将所有与至少另一个文件匹配的文件(不区分大小写)移动到新目录中,其名称中第一个破折号、下划线或空格之前的部分。cd进入你的 jars 目录来运行它。

#!/bin/bash
mkdir -p possible_dups

awk -F'[-_ ]' '
    NR==FNR {seen[tolower($1)]++; next}
    seen[tolower($1)] > 1
' <(printf "%s\n" *.jar) <(printf "%s\n" *.jar) |\
    xargs -r -d'\n' mv -t possible_dups/ --

注意:-r是一个 GNU 扩展,以避免mv在找不到可能的重复项时在没有文件参数的情况下运行一次。此外,GNU 参数-d'\n'通过换行符分隔文件名,这意味着在上面的命令中处理空格和其他常用字符,但不处理换行符。

您可以编辑字段分隔符分配,-F'[-_ ]'以添加或删除字符来定义我们测试重复的部分的结尾。现在它的意思是“破折号、取消划线或空格”。一般来说,捕获比真实重复情况更多的数据是件好事,就像我在这里所做的那样。

现在您可以检查这些文件。如果您觉得文件数量不是很大,您也可以直接对所有文件执行下一步,而不进行过滤。


目视检查可能的重复项

我建议您使用可视外壳来完成此任务,mc例如午夜指挥官。您可以mc使用 Linux 发行版的包管理工具轻松安装。

您可以调用mc包含这些文件的目录,也可以导航到那里。使用 X 终端,您还可以支持鼠标,但任何操作都有方便的快捷方式。

例如,按照菜单操作Left -> Sorting... -> untick "case sensitive"将为您提供所需的排序视图。

使用箭头浏览文件,您可以选择其中的许多文件Insert,然后可以复制 ( F5)、移动 ( F6) 或删除 ( F8) 突出显示的选择。以下是过滤后的测试数据的屏幕截图:

在此输入图像描述

答案2

我们有一个解决方案 我已经接受了这个答案,它可以轻松地实现我的 bash 驱动程序的目标,而不涉及像 MC 或 Ranger 这样的 shell 管理器。

#!/bin/bash

declare -a names

xIFS="${IFS}"
IFS="^M"

while true; do
awk -F'[-_ ]' '
    NR==FNR {seen[tolower($1)]++; next}
    seen[tolower($1)] > 1
' <(printf "%s\n" *.jar) <(printf "%s\n" *.jar) > tmp.dat

        IDX=0
        names=()


        readarray names < tmp.dat

        size=${#names[@]}

        clear
        printf '\nPossible Dupes\n'

        for (( i=0; i<${size}; i++)); do
                printf '%s\t%s' ${i} ${names[i]}
        done

        printf '\nWhich dupe would you like to delete?\nEnter # to delete or q to quit\n'
        read n

        if [ $n == 'q' ]; then
                exit
        fi

        if [ $n -lt 0 ] || [ $n -gt $size ]; then
                read -p "Invalid Option: present [ENTER] to try again" dummyvar
                continue
        fi

        #clean the carriage return \n from the name
        IFS='^M'
        read -ra TARGET <<< "${names[$n]}"
        unset IFS

        # now remove the filename sans any carriage returns
        # from the filesystem
        # 12/18/2020
        rm "${TARGET[*]}" 
        echo "removed ${TARGET[0]}" >> rm.log
done

IFS="${xIFS}"

这对我来说效果很好,因为它不需要尝试读取数百个文件名以查找重复项,并且会循环直到我对结果感到满意为止。它还将我的操作保存到日志文件中。

一般来说,我遇到的重复模组很少,但一旦出现,那就很麻烦了。这个脚本极大地改善了我的这种情况。

如果您能让脚本更加智能或用户友好,我很想看看。

编辑:2020 年 11 月 5 日

  • 改写了我的想法
  • 使用这个脚本好几天了,非常有用
  • 它允许我做的是升级我的客户端包,然后将所有减去客户端模组的内容上传到服务器,然后使用此脚本快速清理服务器模组/文件夹。所以现在我的包维护速度更快了!
  • 更新了脚本以使用 IFS 并清理菜单中的输出

已编辑:2020 年 12 月 18 日

  • 一项微小的更改可以使脚本在更多情况下正常运行。

相关内容