【问题标题】:In bash, how can I remove multiple versions of the same file?在 bash 中,如何删除同一文件的多个版本?
【发布时间】:2021-05-01 17:21:30
【问题描述】:

这可能是一个非常具体的案例,但我对 bash 知之甚少,我需要删除“重复”文件。这几天我一直在下载完全合法的电子游戏 rom,我注意到很多包都有同一个游戏的许多不同版本,就像这样:

Awesome Golf (1991).lnx
Awesome Golf (1991) [b1].lnx
Baseball Heroes (1991).lnx
Baseball Heroes (1991) [b1].lnx
Basketbrawl (1992).lnx
Basketbrawl (1992) [a1].lnx
Basketbrawl (1992) [b1].lnx
Batman Returns (1992).lnx
Batman Returns (1992) [b1].lnx

如何制作删除重复项的 bash 脚本?副本将是具有相同名称的任何文件,并且名称将是第一个括号之前的字符串。该脚本应该解析所有文件并获取它们的名称,查看哪些名称匹配以检测重复项,并删除除第一个文件之外的所有文件(第一个是按字母顺序出现的第一个文件)。

【问题讨论】:

  • 哪些是重复的?那些有[a1][b1]等的人?
  • 同名者。想法是将具有相同名称的所有内容(即括号之前的所有内容)视为重复,并删除除第一个之外的所有内容。
  • 用这些额外的细节更新问题(不是每个人都会通读 cmets 试图拼凑整个画面);也...对于给定的示例输入...更新问题 a) 你到目前为止尝试过的内容,b) 你的代码生成的(错误的)结果和 c) (正确的)期望输出;另一件事,用实际文件名的文本/代码块替换图像......我们可以(轻松地)剪切粘贴到测试用例中(即,我们对花时间将图像转换为文本不感兴趣)
  • 您最好先获取所有文件的 MD5 摘要(校验和),然后查找重复项(通过sortuniq -d 进行管道传输),然后删除名称最长的重复项。
  • 学会使用git下次会很有用

标签: bash automation scripting


【解决方案1】:

请您尝试以下方法:

#!/bin/bash

dir="dir"                               # the directory where the rom files are located
declare -A seen                         # associative array to detect the duplicates
while IFS= read -r -d "" f; do          # loop over filenames by assigning "f" to it
    name=${f%(*}                        # extract the "name" by removing left paren and following characters
    name=${name%.*}                     # remove the extension considering the case the filename doesn't have parens
    name=${name%[*}                     # remove the left square bracket and following characters considering the case as above
    name=${name%% }                     # remove trailing whitespaces, if any
    if (( seen[$name]++ )); then        # if the name duplicates...
        # remove "echo" if the output looks good
        echo rm -- "$f"                 # then remove the file
    fi
done < <(find "$dir" -type f -name "*.lnx" -print0 | sort -z -t "." -k1,1)
                                        # sort the list of filenames in alphabetical order
  • 请将第一行dir= 修改为存放rom 文件的目录路径。
  • echo 命令只是打印要删除的文件名作为排练。如果输出看起来不错,则删除 echo 并执行真实的。

[解释]

  • 关联数组seen 将提取的“名称”与 外观计数器。如果计数器不为零,则文件是重复的 一个并且可以删除(只要文件正确排序)。
  • -print0 选项到find-z 选项到sort-d "" read 的选项将空字符作为文件名的分隔符 接受包含特殊字符(例如空格)的文件名, 制表符、换行符等。

【讨论】:

  • 这很完美!它会引发一些“错误的数组下标”错误,但它确实删除了它需要的所有内容,太好了。非常感谢。
  • 感谢您的反馈。如果关联数组的键为空,则可能会出现“坏数组下标”错误。这是一个意想不到的行为,但如果最终结果符合您的要求,那就没问题了。如果您想修复错误,请告诉我。
  • 好吧,我确实注意到,如果文件没有括号,那么它将永远不会匹配,因为存在扩展名。假设我们有Game1 (b1).extGame1.ext,脚本将删除第一个示例中括号后的所有内容,但它会保留第二个字符串的扩展名,因此当比较它们时它不会匹配并且他们不会被删除。该脚本确实已经帮助了我很多,但是如果您知道如何解决这个问题,我将不胜感激。正如我所说,可悲的是,我基本上不知道 bash。
  • 我可以假设扩展名总是.lnx吗?
  • 让我确认一下。上述文件名是Game1 (b1).lnx,而不是Game1 [b1].lnx
猜你喜欢
  • 1970-01-01
  • 2012-05-17
  • 2015-06-07
  • 2018-01-16
  • 1970-01-01
  • 2013-03-11
  • 1970-01-01
  • 2023-04-04
  • 2019-07-19
相关资源
最近更新 更多