Perl:查找匹配项,删除相同的行,并获取最后一个字段

时间:2016-10-14 18:01:44

标签: perl

作为Perl新手,请原谅我提出这个基本问题。

我有一个文本文件@ server1,它在文件的许多行上显示了一堆句子(空格是字段分隔符)。

我需要使用我的关键字匹配行,删除相同的行,并仅提取最后一个字段,所以我尝试过:

my @allmatchedlines;

open(output1, "ssh user1@server1 cat /tmp/myfile.txt |");

    while(<output1>) {
            chomp;
            @allmatchedlines = $_ if /mysearch/;
    }
    close(output1);

    my @uniqmatchedline = split(/ /, @allmatchedlines);

    my $lastfield = $uniqmatchedline[-1]\n";
    print "$lastfield\n";

它给我输出显示: 1

我不知道为什么它只给了我&#34; 1&#34;。

有人可以解释为什么我会得到&#34; 1&#34;以及如何正确获取匹配线的最后一个字段?

谢谢!

3 个答案:

答案 0 :(得分:2)

my @uniqmatchedline = split(/ /, @allmatchedlines);

你得到“1”因为split占用标量,而不是数组。标量上下文中的数组返回元素数。

您需要拆分每条线。像这样:

my @uniqmatchedline = map { split(/ /, $_) } @allmatchedlines;

答案 1 :(得分:1)

您的代码存在两个问题:

  1. split期待分割的标量值(字符串);如果你传递一个数组,它会将数组转换为标量(这只是数组长度)

  2. 您无法删除相同的行

  3. 要解决这些问题,以下代码应该有效(未作为无数据进行测试):

    my @allmatchedlines;
    
    open(output1, "ssh user1@server1 cat /tmp/myfile.txt |");
    
    while(<output1>) {
            chomp;
            @allmatchedlines = $_ if /mysearch/;
    }
    close(output1);
    
    my %existing;
    my @uniqmatchedline = grep !$existing{$_}++, @allmatchedlines;  #this will return the unique lines
    
    my @lastfields = map { ((split / /, $_)[-1]) . "\n" } @uniqmatchedline ; #this maps the last field in each line into an array
    
    print for @lastfields;
    

答案 2 :(得分:0)

除了代码中的两个错误之外,我发现语句&#34; 删除相同的行并仅提取最后一个字段&#34;不清楚。一旦删除重复的匹配行,模式可能仍然存在多个不同的句子。

在澄清之前,这里是从最后一个句子中选择最后一个字段的代码

use warnings 'all';
use strict;

use List::MoreUtils qw(uniq)

my $file = '/tmp/myfile.txt';
my $cmd  = "ssh user1\@server1 cat $file";

open my $fh, '-|', $cmd  // die "Error opening $cmd: $!";  # / 

while (<$fh>) {
    chomp;
    push @allmatchedlines, $_ if /mysearch/;
}
close(output1);

my @unique_matched_lines = uniq @allmatchedlines;

my $lastfield = ( split ' ', $unique_matched_lines[-1] )[-1]; 

print $lastfield, "\n";

我更改为三参数open,并进行错误检查。回想一下,进程的open涉及一个fork并返回pid,所以&#34;错误&#34;根本不涉及命令本身发生的事情。见open。 (# /仅关闭错误的语法突出显示。)另请注意@下的"..."表示数组,因此需要进行转义。

split中使用的(默认)模式' '会分割任意数量的空白。正则表达式/ /关闭此行为并在单个空格上拆分。您最有可能想使用' '

如需更多评论,请参阅以下原始帖子。

每次迭代的语句@allmatchedlines = $_ if /mysearch/; 分配给数组,覆盖其中的任何内容。因此,您最终只得到与mysearch匹配的最后一行。您希望push @allmatchedlines, $_ ...获取所有这些行。

此外,如Justin Schell的答案所示,split需要一个标量,因此它的长度为@allmatchedlines - 如上所述为1。你应该

my @words_in_matched_lines = map { split } @allmatchedlines;

当所有这些都被理顺时,你会在数组@uniqmatchedline中有单词,如果这是意图,那么它的名字就会产生误导。

要获取阵列的唯一元素,您可以使用模块List::MoreUtils

use List::MoreUtils qw(uniq);

my @unique_elems = uniq @whole_array;