我正在用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?
答案 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附带了核心模块Socket和Net::hostent。
我已经将v5.24用于非常好的postfix dereferencing功能->@*
,它将数组引用从addr_list
转换为map
可以使用的常规列表
你需要注意放在$cmd
中的任何内容。我在Mastering Perl的“安全”一章中详细讨论了这一点。您还可以在perlsec文档中找到一些内容。
答案 3 :(得分:2)
在Socket
模块的inet_aton
和inet_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"]