比较文件内容并删除较短的内容

时间:2018-04-25 02:06:33

标签: linux file cygwin

我有成千上万的.txt文件。我想删除其中一些。一些文件是相似的 - 相同的内容,但一个更长,我需要删除较短的文件。所有文件都放在一个文件夹中。

对这些文件唯一了解的是一个文件可以包含内容

ABCDEFGH

和另一个

ABCDEF

但不是

XYZ

我需要做的是删除具有类似较长ABCDEF文件的文件ABCDEFGH。我期待n *(n-1)比较。假设应以二进制形式比较文件。在bash(或者通常是Linux)中是否有一个脚本可以为我做这个?如果我必须这样做,我会写一个C#控制台应用程序来比较所有文件并删除类似但更短的文件,但我认为它在bash脚本(或在Linux上)会更容易和更快。允许使用外部工具。如果文件具有相同的内容且长度相同 - 其中一个文件必须保留在文件夹中。可能会有3个或更多文件(具有相同内容)和(相同长度或不同长度)。

3 个答案:

答案 0 :(得分:0)

任何对这种Perl脚本感兴趣的人都会很高兴。我假设我们在当前文件夹中带有* .txt文件的脚本。如果该文件与其他文件相同,但更长或更短,则其中一个文件中有一些数据会使该文件变长,但对于前半部分而言没有什么不同,则该较短的文件将被删除。对于1.3MB和1300个文件,Cygwin Perl用了不到2分钟的时间浏览了所有文件。逐行比较文件。以下脚本:

#!/usr/bin/env perl
use strict;
use warnings;

my @files = <*.txt>;
my @del;
my $diff;
foreach my $file1 (@files) {
        foreach my $file2 (@files) {
                if ($file1 eq $file2) {
                        last;
                }
                open my $fh1, $file1 or die "can't open $file1: $!";
                open my $fh2, $file2 or die "can't open $file2: $!";
                print "Comparing $file1 and $file2...";
                my $line1;
                my $line2;
                $diff=0;
                while($line1 = <$fh1>) {
                        $line2 = <$fh2>;
                        if ($line1 ne $line2) {
                                print "different!\n";
                                $diff=1;
                                last;
                        }
                }
                if ($diff == 0) {
                        print "the same till end of one files!\n";
                        if (-s $file1 >= -s $file2)
                        {
                                push @del, $file2;
                        }
                        if (-s $file1 < -s $file2)
                        {
                                push @del, $file1;
                        }
                }
                close($fh1);
                close($fh2);
        }
}
foreach my $file (@del) {
        print "Removing $file\n";
        unlink $file;
}

请注意,文件和行尾的编码可能会有所不同,因此,所有文件(例如)应采用UTF-8编码,并且行尾应相同-LF。

答案 1 :(得分:-1)

尝试使用以下脚本(我没有包含rm命令,仅用于echo用于测试目的):

#!/usr/bin/env bash

# Create some files for testing
touch ABCDEF                                                             
touch ABC
touch ACB
touch XABC  
touch XYZ                                                                                                                      
touch XY 

for fname1 in *; do                                                      
    for fname2 in *; do                                                  
        if [[ "$fname2" != "$fname1" && "$fname2" =~ "$fname1" ]]; then  
            echo -e "Short: $fname1 \tLong: $fname2"
        fi                                                               
    done                                                                 
done 

此脚本仅搜索当前目录中的文件。输出:

Short: ABC    Long: ABCDEF                                                  
Short: ABC    Long: ABCDEFGH 
Short: ABC    Long: XABC                                               
Short: ABCDEF Long: ABCDEFGH                                             
Short: XY     Long: XYZ 

如果你想删除&#34;短&#34;然后用{/ 1>替换echo

rm -i "$fname1" 2>/dev/null                                              

我没有优化此代码,因此可能效率低下。如果是这种情况,请告诉我,我会尽力改进。

答案 2 :(得分:-1)

您的问题并未说明您是在谈论文件名还是文件内容。我假设文件名,因为这可能是一个单行。

以下可能会:

$ shopt -s nullglob
$ for f in *; do for x in "$f"?*; do rm -v "$f"; continue 2; done; done
  • 逐步执行您的文件列表(*),将每个文件分配给$f
  • 对于每个文件,它使用一轮内部for循环来确定 是否存在更长版本的文件名。
  • 如果版本较长 存在,删除较短的版本,我们继续 外环。

nullglob shell选项使我们无需测试文件$x是否存在。