在shell中,如何删除编号的重复文件?

时间:2012-10-03 17:03:49

标签: bash awk

我有一个包含几千个文件的目录,名称如下:

filename.ext
filename (1).ext
filename (2).ext
otherfile.ext
otherfile (1).ext
etc.

大多数带有括号的数据都是原始文件的副本,但在某些情况下它们不是。

如何保留原始文件,删除重复文件,但不丢失不同的文件?

我知道我可以rm *\).ext,但这显然无法确保文件与原始文件相符。

我正在使用OS X,所以我有一个md5程序,其功能类似于Linux中的md5sum,尽管它将哈希值放在行的末尾而不是开头。我以为我可以使用awk脚本获取md5 *.ext | awk 'some script'的输出,通过md5查找重复项,然后删除它们,但命令行太长(bash: /sbin/md5: Argument list too long)。

我不知道在脚本中要写什么。我想用这个来存储数组:

awk '{a[$NF]++} a[$NF]>1{sub(/).*/,""); sub(/.*(/,""); system("rm " $0);}'

但这似乎总是删除我原来的。

我做错了什么?我该怎么做?

感谢。

2 个答案:

答案 0 :(得分:6)

您的awk脚本会删除原始文件,因为在对文件进行排序时,.(句点)会在(空格)之后排序。所看到的第一个文件是编号的,而不是原始文件,后续检查(包括原始文件)与第一个编号的文件进行比较。

rm *\).txt不仅与原作不匹配,而且首先会丢失可能没有原始文件的文件。

我不会这样做。您可以浏览原始列表,然后删除与其匹配的编号文件,而不是检查每个编号文件并验证它是否与原始文件匹配。

相反:

$ for file in *[^\)].txt; do echo "-- Found: $file"; rm -v $(basename "$file" .txt)\ \(*\).txt; done

您可以展开此选项以检查MD5。但它的代码更多,所以我会在脚本中将它分成多行:

#!/bin/bash

shopt -s nullglob              # Show nothing if a fileglob matches no files

for file in *[^\)].ext; do
  md5=$(md5 -q "$file")        # The -q option gives you only the message digest
  echo "-- Found: $file ($md5)"
  for duplicate in $(basename "$file" .ext)\ \(*\).ext; do
     if [[ "$md5" = "$(md5 -q "$duplicate")" ]]; then
        rm -v "$duplicate"
     fi
  done
done

作为替代方案,您可以更轻松地完成此操作,与计算MD5摘要相比,CPU开销更少。 Unix和Linux有一个名为cmp的shell工具,它与没有输出的diff类似。所以:

#!/bin/bash

shopt -s nullglob

for file in *[^\)].ext; do
  for duplicate in $(basename "$file" .ext)\ \(*\).ext; do
    if cmp "$file" "$duplicate"; then
      rm -v "$file"
    fi
  done
done

答案 1 :(得分:0)

如果你不需要使用AWK,你可以在bash中做一些更简单的事情:

for file in *\([0-9]*\)*; do
    [ -e "$(echo "$file" | sed -e 's/ ([0-9]\+)//')" ] && rm "$file"
done

希望这有点帮助=)