查找内容重复的文本文件?

查找内容重复的文本文件?

我错误地附加了 (>>) 而不是覆盖 (>) 处理数千个文件的脚本的输出,但我只对大约 20% 的文件执行了此操作(我运行了该脚本的 5 个并行实例)。基本上我有十行文本,一个空行,然后又是相同的十行文本。

  1. 我怎样才能找到这些文件?
  2. 如何删除第二次迭代?

1比2重要得多。

我错误地附加了 (>>) 而不是覆盖 (>) 处理数千个文件的脚本的输出,但我只对大约 20% 的文件执行了此操作(我运行了该脚本的 5 个并行实例)。基本上我有十行文本,一个空行,然后又是相同的十行文本。

  1. 我怎样才能找到这些文件?
  2. 如何删除第二次迭代?

1比2重要得多。

(这个问题就说明了问题)


更新:

我仔细看了看内容。这是具有重复内容的文件的结构:

<empty line>
<text>
<empty line>
<empty line>
<same text>
<empty line>

没有重复内容的文件是

<empty line>
<text>
<empty line>

也就是说,中间有两行空行,第一行的起点是上面的文字,第二行的起点是下面的文字。文本的顶部和底部均被一行空行包围。

答案1

  1. 在执行其他操作之前,请先备份当前的数据。如果出现任何问题,您可以随时恢复到此副本。例如你可以用来tar这样做:

    tar cfz /path/to/backup-files.tar.gz /path/to/directory-to-backup/
    

    作为一般规则,您应该绝不处理您关心的任何数据的唯一副本。请务必进行备份,或制作副本并在副本上进行操作。换句话说:你应该总是给自己一个简单、最好是快速的方法来恢复任何更改、撤消任何错误。

  2. 如果您绝对确定\n任何“好”文件中都不会连续出现三个换行符 ( ) 的实例,那么请尝试此操作副本一些“好”和“坏”文件:

    perl -i -0777 -p -e 's/\n{3,}.*/\n\n/' filenames
    

    这将删除这些文件中从 3 个换行符(即一行文本末尾的换行符后跟两个空行)到文件末尾的所有内容,并将其替换为两个换行符(一个用于结束文本行) ,以及您想要在文件末尾添加的空行)。

    任何文件有 3 个连续的换行符(即它们是不需要修复的“好”文件),将不会被修改。

  3. 检查刚刚用 perl 处理的文件(“好”和“坏”)。

    如果它们符合您的预期,则对包含您的文件的目录中的所有文件运行 perl 脚本。例如,find如果文件都有.txt扩展名:

    find /path/to/directory -type f -name '*.txt' -exec \
      perl -i -0777 -p -e 's/\n{3,}.*/\n\n/' {} +
    

    (调整find命令以适合您的实际目录和文件名)

答案2

使用 GNU awk for multi-char RS 和 ENDFILE 只是为了查找文件:

$ awk -v RS='\n{2}' '$0==p{f=1} {p=$0} ENDFILE{print FILENAME, (f ? "dups" : "uniq"); p=f=""}' file1 file2
file1 dups
file2 uniq

以上是在此输入上运行的:

$ head file{1,2}
==> file1 <==

<text>


<text>


==> file2 <==

<text>

答案3

perl

find . -type f -size +1c -exec perl -l -0777 -e '
  while (<<>>) {
    $size = length; $half = $size / 2;
    if ($size % 2 == 0 && substr($_, 0, $half) eq substr($_, $half)) {
      print "$ARGV is one of them";
      truncate $ARGV, $half or warn "truncate $ARGV: $!";
    }
  }' {} +

答案4

在 中zsh,您可以使用$mapfile关联数组将文件路径映射到其内容。这样可以轻松比较前半部分和后半部分并就地更新文件。

#! /bin/zsh -
zmodload zsh/mapfile || exit
set +o multibyte

for file in **/*(ND.L+1); do
  text=$mapfile[$file]
  size=$#text
  if (( size % 2 == 0 )); then # even size
    (( half = size / 2 ))
    if [[ $text[1,half] = $text[half+1,-1] ]]; then
      print -r -- $file is one of them
      mapfile[$file]=$text[1,half] # or truncate -s$half -- $file
    fi
  fi
done

(未经测试)。

您可以替换**/*(ND.L+0)**/*(ND.L+0m-1)仅处理过去 24 小时(或**/*(ND.mh-3)过去 3 小时等)内最后修改的文件。D如果不需要考虑隐藏文件,请删除。删除或注释掉 ,mapfile[$file]=...仅列出匹配的文件而不修改它们。

相关内容