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

Posted

技术标签:

【中文标题】如何在perl中使用split函数来完成awk的工作【英文标题】:How to use split function in perl to do the work of awk 【发布时间】:2017-01-19 15:15:57 【问题描述】:

我正在用 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 函数(可能是拆分或映射)而不是使用 awk 和 tr?

【问题讨论】:

输入和期望的输出? 地址总是 IPv4 吗? 【参考方案1】:

琐碎。默认情况下splitawk 一样工作。所以:

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

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

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

【讨论】:

太好了,谢谢! ,关于“tr”命令我能做些什么吗? 是的。但我不会,因为 那个 位正在使用xargs 运行多个命令,而我只是在perl 中一次运行一个命令。【参考方案2】:

perl one liner 类似用途

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

-n 为文件创建循环

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

【讨论】:

也非常感谢!【参考方案3】:

如果你知道你想要的字段是最后一列,你可以使用从末尾倒数的索引:

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

在单行情况下,使用-a 开关使Perl 将行拆分为@F 数组(-nwhile(&lt;&gt;)... 包裹在-e 的参数周围,-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 将命令的输出分成几行。核心模块Socket 和Net::hostent 随Perl 一起提供。

我使用 v5.24 是因为它非常棒的 postfix dereferencing 功能 -&gt;@*,它将来自 addr_list 的数组引用转换为 map 可以使用的常规列表。

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

【讨论】:

非常感谢您的详细解答!【参考方案4】:

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.***.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 qqUnable to convert host name "$name": $!\n;

    inet_ntoa($add32);

输出

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

【讨论】:

【参考方案5】:

perl oneliners 来救援 - 列出我的出租车收据,按第 4 列排序,带有 _token delim:

    ls -1 | sort -t'_' -k 4| grep -i taxi
    00016,70_2021-12-04_OL_2021-12-04_id-10_LahiTaxi-Oy_TaxiKuljetus.jpg
    00125,10_2021-12-04_OL_2021-12-04_id-11_Tom-Lindroos_Taxipalvelut.jpg

将它们视为一个表(对于控制台中的每一行,抓取到 @a 数组(这可能更短...),而不是通过它的索引来引用数组的每个元素:

ls -1 | sort -t'_' -k 4|perl -ne 'chomp($_);@a=split/_/;print "$a[4]\t$a[3]\t$a[2]\t$a[1]\t$a[5]\t$a[6]\t$a[0]\n"' | grep -i taxi

    id-10   2021-12-04      OL      2021-12-04      LahiTaxi-Oy     TaxiKuljetus.jpg        00016,70
    id-11   2021-12-04      OL      2021-12-04      Tom-Lindroos    Taxipalvelut.jpg        00125,10

将它们放入 csv 文件中,以导入到 xls、google sheet:

  ls -1 | sort -t'_' -k 4|perl -ne 'chomp($_);@a=split/_/;print "$a[4];$a[3];$a[2];$a[1];$a[5];$a[6];$a[0]\n"' > ../lst.csv

【讨论】:

以上是关于如何在perl中使用split函数来完成awk的工作的主要内容,如果未能解决你的问题,请参考以下文章

如何将数组的值作为第二个参数传递给 awk 的 split 函数?

awk中split函数的用法

linux下awk内置函数的使用(split/substr/length)

Perl学习

如何在 sed 和 awk(和 perl)中搜索和替换任意文字字符串

如何 grep/perl/awk 重叠正则表达式