作为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;以及如何正确获取匹配线的最后一个字段?
谢谢!
答案 0 :(得分:2)
my @uniqmatchedline = split(/ /, @allmatchedlines);
你得到“1”因为split占用标量,而不是数组。标量上下文中的数组返回元素数。
您需要拆分每条线。像这样:
my @uniqmatchedline = map { split(/ /, $_) } @allmatchedlines;
答案 1 :(得分:1)
您的代码存在两个问题:
split期待分割的标量值(字符串);如果你传递一个数组,它会将数组转换为标量(这只是数组长度)
您无法删除相同的行
要解决这些问题,以下代码应该有效(未作为无数据进行测试):
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;