从文件中删除多行重复

时间:2018-07-04 16:26:16

标签: perl duplicates

我在crontab中运行了一个Perl脚本,该脚本生成了一个包含重复条目的文件,因为在每次运行时,它都会重写先前编写的信息。

我会使用文件sort -u,但是我会在Perl脚本文件的末尾使用它。

我的列表

10/10/2017 00:01:39:000;Sagitter
10/11/2017 00:00:01:002;Lupus
10/12/2017 00:03:14:109;Leon
10/12/2017 00:09:00:459;Sagitter
10/13/2017 01:11:03:009;Lupus
12/13/2017 04:29:00:609;Ariet
10/11/2017 00:00:01:002;Lupus
10/12/2017 00:03:14:109;Leon
...

我的代码

#!/usr/bin/perl

# Libraries
use strict;
use warnings 'all';

%lines = ();

# Remove duplicate

open( TMP_GL_OUTPUT, '>', $OUTPUT_FILE ) or die $!;

while ( <TMP_GL_OUTPUT> ) {
    $lines{$_}++;
}

open( OUTFILE, '>', $TMPOUTPUT_FILE ) or die $!;
print OUTFILE keys %lines;
close( OUTFILE );

close( TMP_GL_OUTPUT );

我要去哪里错了?在外壳中感觉比在Perl中短。

sort -u $TMPOUTPUT_FILE > $OUTPUT_FILE 

根据ikegamy用户的建议,我已执行以下操作:

move $OUTPUT_FILE, $TMPOUTPUT_FILE; # Copy file
run [ 'sort', '-u', '--', $TMPOUTPUT_FILE ], '>', $OUTPUT_FILE; # Remove duplicate
unlink $TMPOUTPUT_FILE;

3 个答案:

答案 0 :(得分:6)

我想你是在问为什么Perl程序比shell脚本长。

首先,您的shell脚本执行的操作与Perl程序完全不同。

  • 您的shell脚本执行一个程序,并将其存储在文件中。
  • 您的Perl程序读取文件,处理读取的数据,并将输出存储在文件中。

Perl等同于

sort -u -- "$TMPOUTPUT_FILE" > "$OUTPUT_FILE"

use IPC::Run qw( run );

run [ 'sort', '-u', '--', $TMPOUTPUT_FILE ], '>', $OUTPUT_FILE;

(这两者之间的错误处理有所不同。)

它们的长度没有什么不同。

这带来了第二个区别。 Shell专门执行程序,但是Perl是通用语言。如果在Perl中不再使用它,将是令人惊讶的!

(现在尝试将Perl程序的大小与sort的来源进行比较...)

答案 1 :(得分:1)

List :: Util是一个核心模块。

use List::Util 'uniq';

print for uniq <>

答案 2 :(得分:0)

您的代码看起来几乎可以。

在您开始之前,我只建议chomp每行 将元素保存在哈希中。

原因是最后一行,未终止 \n的情况可能与前一行相同, 但如果没有chomp,前一行将包含 结束的\n,最后一个-不。

结果是这两行都是哈希中的不同键。

将我的示例程序(工作状态,如下所示)与您的进行比较,有 除了读取__DATA__和 写入控制台。

在我的程序中,出于演示目的,我放入了两种打印输出变体, 一个带有键值(重复计数),另一个仅打印键。 在您的程序中仅保留第二个打印输出。

use strict; use warnings; use feature qw(say);

my %lines;
while(<DATA>) {
    chomp;
    $lines{$_}++;
}
while(my($key, $val) = each %lines) {
    printf "%-32s / %d\n", $key, $val;
}
say '========';
foreach my $key (keys %lines) {
    say $key;
}
__DATA__
10/10/2017 00:01:39:000;Sagitter
10/11/2017 00:00:01:002;Lupus
10/12/2017 00:03:14:109;Leon
10/12/2017 00:09:00:459;Sagitter
10/13/2017 01:11:03:009;Lupus
12/13/2017 04:29:00:609;Ariet
10/11/2017 00:00:01:002;Lupus
10/12/2017 00:03:14:109;Leon

编辑

您的代码未为$OUTPUT_FILE$TMPOUTPUT_FILE分配名称, 您甚至没有声明这些变量,但我认为,在您的实际 代码完成了。

另一个细节是%lines之前应加上my, 否则,当您放置use strict;时,编译器将打印错误。

编辑2

有比您更快,更短的解决方案。

而不是将行写到哈希表中,直到将它们打印到 第二步,您可以在单个循环中完成该操作:

  • 阅读该行。
  • 检查哈希是否已经包含与刚读取的行相同的键。
  • 如果不是,则:
    • 将行写入哈希,以阻止打印输出,如果只是 同一行再次出现
    • 打印行。

您甚至可以将其编写为Perl单行代码:

perl -lne"print if !$lines{$_}++" input.txt

如果从Windows cmd运行上述命令,它将打印输出 到控制台。如果您使用Linux,则可以使用撇号代替双引号。

您当然可以将输出重定向到任何文件,将> output.txt添加到 上面的命令。

由于-l选项的限制,为每个输入行执行了代码。

如果您不了解有关Perl单线的任何其他详细信息,请在网上搜索。