比较文件内容并删除较短的文件
Compare files content and delete shorter ones
我有数千个 .txt 文件。我想删除其中的一些。有些文件很相似——内容相同,但有一个较长,我需要删除较短的一个。所有文件都放在一个文件夹中。
关于这些文件唯一已知的是一个文件可以有内容
ABCDEFGH
另一个
ABCDEF
但不是
XYZ
我需要做的是删除文件 ABCDEF
,它有一个类似的更长的 ABCDEFGH
文件。我希望进行 n*(n-1) 次比较。假设文件应该以二进制形式进行比较。 bash(或者通常是 Linux)中是否有脚本可以为我做这件事?如果我必须这样做,我会编写一个 C# 控制台应用程序来比较所有文件并删除相似但较短的文件,但我认为在 bash 脚本(或 Linux).允许使用外部工具。如果文件具有相同的内容且长度相同 - 其中一个文件必须保留在文件夹中。有可能会有3个或更多文件(内容相同)和(相同长度或不同长度)。
尝试以下脚本(我没有包含 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
如果要删除 "short" 文件,请将 echo
行替换为
rm -i "$fname1" 2>/dev/null
我没有优化这段代码,所以它可能效率低下。如果是这种情况请告诉我,我会尽力改进。
您的问题没有具体说明您是在谈论文件名还是文件内容。我将假设文件名,因为这可以作为一个单行。
以下可能会做:
$ shopt -s nullglob
$ for f in *; do for x in "$f"?*; do rm -v "$f"; continue 2; done; done
- 这会遍历您的文件列表 (
*
),将每个文件分配给 $f
。
- 对于每个文件,它使用一轮内部for循环来确定
是否存在更长版本的文件名。
- 如果版本较长
存在,删除较短的版本,我们继续
外环。
nullglob
shell 选项使我们不必测试文件 $x
.
是否存在
任何对这种 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。
我有数千个 .txt 文件。我想删除其中的一些。有些文件很相似——内容相同,但有一个较长,我需要删除较短的一个。所有文件都放在一个文件夹中。
关于这些文件唯一已知的是一个文件可以有内容
ABCDEFGH
另一个
ABCDEF
但不是
XYZ
我需要做的是删除文件 ABCDEF
,它有一个类似的更长的 ABCDEFGH
文件。我希望进行 n*(n-1) 次比较。假设文件应该以二进制形式进行比较。 bash(或者通常是 Linux)中是否有脚本可以为我做这件事?如果我必须这样做,我会编写一个 C# 控制台应用程序来比较所有文件并删除相似但较短的文件,但我认为在 bash 脚本(或 Linux).允许使用外部工具。如果文件具有相同的内容且长度相同 - 其中一个文件必须保留在文件夹中。有可能会有3个或更多文件(内容相同)和(相同长度或不同长度)。
尝试以下脚本(我没有包含 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
如果要删除 "short" 文件,请将 echo
行替换为
rm -i "$fname1" 2>/dev/null
我没有优化这段代码,所以它可能效率低下。如果是这种情况请告诉我,我会尽力改进。
您的问题没有具体说明您是在谈论文件名还是文件内容。我将假设文件名,因为这可以作为一个单行。
以下可能会做:
$ shopt -s nullglob
$ for f in *; do for x in "$f"?*; do rm -v "$f"; continue 2; done; done
- 这会遍历您的文件列表 (
*
),将每个文件分配给$f
。 - 对于每个文件,它使用一轮内部for循环来确定 是否存在更长版本的文件名。
- 如果版本较长 存在,删除较短的版本,我们继续 外环。
nullglob
shell 选项使我们不必测试文件 $x
.
任何对这种 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。