如何在perl中使用split函数来完成awk

时间:2016-09-12 08:17:24

标签: regex perl awk

我正在用perl编写脚本,我想尽可能避免使用外部命令作为awk,tr等。 这是我在脚本中运行的命令,使用反引号:

my @arr = `$cmd | tr " " "\n" | xargs -n1 host | awk '{print $4}'`

这是输出awk '{print 4$}

$fileserver has address 10.90.207.59
$fileserver has address 10.90.207.34
$fileserver has address 10.90.207.56
$fileserver has address 10.90.207.67

这是awk '{print 4$}的输出:

10.90.207.59
10.90.207.34
10.90.207.56
10.90.207.67

我希望每个IP都在数组中的单独单元格中。 如何使用perl函数(可能是split或map)而不是使用awk和tr?

4 个答案:

答案 0 :(得分:5)

中平凡。默认情况下,split的工作方式与awk类似。所以:

my @arr = split;
print $arr[3]; #note - arrays start at zero. 

然而,perl通常也会在文件句柄上逐行工作,而split可以获得你不想要的东西。

你可以:

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

while (<DATA>) {
   my ($ip) = (split)[3];
   print $ip, "\n";
   #or push it. 
}

__DATA__
$fileserver has address 10.90.207.59
$fileserver has address 10.90.207.34
$fileserver has address 10.90.207.56
$fileserver has address 10.90.207.67

但如果你正在寻找一个单一的东西:

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;

my @ips = map { (split)[3] } <DATA>;

print Dumper \@ips;


__DATA__
$fileserver has address 10.90.207.59
$fileserver has address 10.90.207.34
$fileserver has address 10.90.207.56
$fileserver has address 10.90.207.67

我们在列表上下文中读取<DATA>,因此它返回整个内容 - 一次一个元素来映射。

然后在map我们拆分每个,并以awk术语抓取元素3$4)。

答案 1 :(得分:4)

类似用途perl one liner

perl -nae 'print "$F[3]\n"' input.txt

-n为文件制作循环

-a autosplit模式。默认情况下用空格分割。输出存储在@F中。所以我使用第三个索引来打印ip地址。在perl索引中以0开始

答案 2 :(得分:3)

如果您知道所需的字段是最后一列,则可以使用从结尾开始向后计数的索引:

my $ip = (split)[-1];

在单行情况下,使用-a开关使Perl将行拆分为@F数组(-n包围while(<>){...}围绕参数-e 1}}和-l为每个print添加换行符(请参阅perlrun)):

perl -anle 'print $F[-1]'

但是,既然你没有坚持使用awk,那么就不必这样做了。你可以在没有管道的情况下在Perl中完成大部分工作。以下是您的开始:

my @arr = `$cmd | tr " " "\n" | xargs -n1 host | awk '{print $4}'`

看起来$cmd在一行中生成了一堆主机名。您可以使用tr将空格转换为换行符,然后在每行上运行host。对于每个host输出,您可以获取地址。

您可以在单个Perl程序中执行此操作:

 use v5.24;

 use Socket;        # core module
 use Net::hostent;  # core module

 my $cmd = ...;
 foreach my $host ( `$cmd` ) {
      chomp( $host );
      my @addresses = 
          map { inet_ntoa($_) } 
          gethostbyname($host)->addr_list->@*;
      say join "\n", @addresses;
     }

使用列表上下文中的反引号,Perl会将命令的输出分成多行。 Perl附带了核心模块SocketNet::hostent

我已经将v5.24用于非常好的postfix dereferencing功能->@*,它将数组引用从addr_list转换为map可以使用的常规列表

你需要注意放在$cmd中的任何内容。我在Mastering Perl的“安全”一章中详细讨论了这一点。您还可以在perlsec文档中找到一些内容。

答案 3 :(得分:2)

Socket模块的inet_atoninet_ntoa的帮助下,您可以非常简单地在Perl中执行整个操作,但$cmd除外,因为您不要告诉我们那是什么

看起来你的$cmd会返回一行或多行主机名,用空格分隔,所以我在这里使用echo命令来模拟它。我还使用Data::Dump来揭示@addresses

的最终内容
use strict;
use warnings 'all';

use Socket;

my $cmd = 'echo www.amazon.co.uk www.perl.com www.stackoverflow.com';

my $cmd_output = `$cmd`;
my @addresses = map { name_to_ip($_) } split ' ', $cmd_output;

use Data::Dump;
dd \@addresses;

sub name_to_ip {

    my ($name) = @_;
    my $add32 = inet_aton($name) or die qq{Unable to convert host name "$name": $!\n};

    inet_ntoa($add32);
}

输出

["54.239.36.155", "207.171.7.72", "151.101.193.69"]