Reputation: 487
I am writing a script in perl and I want to avoid using external commands as awk, tr , etc as much as possible. This is the command I am running from inside the script , using backticks:
my @arr = `$cmd | tr " " "\n" | xargs -n1 host | awk '{print $4}'`
And this is the output with out 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
This is the output with awk '{print 4$}
:
10.90.207.59
10.90.207.34
10.90.207.56
10.90.207.67
I want each IP to be in a separated cell in the array. How can I use perl functions (maybe split or map) currectrly instead of using awk and tr?
Upvotes: 2
Views: 905
Reputation: 5430
perl oneliners to the rescue - list my taxi receipts, sort by the 4th col, with _
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
seem them as a table (for each row in the console, grab into the @a
array ( this could be even shorter ... ) , than refer to each element of the array by it's index:
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
put them into a csv file, to import into 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
Upvotes: 0
Reputation: 132858
If you know that the field that you want is the last column, you can use an index that counts backward from the end:
my $ip = (split)[-1];
In the one-liner case, using the -a
switch makes Perl split the line into the @F
array (the -n
wraps while(<>){...}
around the argument to -e
and the -l
adds a newline to each print
(see perlrun)):
perl -anle 'print $F[-1]'
However, since you're not stuck with awk, you don't have to do it that way. You can probably do most of that in Perl without the pipeline. Here's what you started with:
my @arr = `$cmd | tr " " "\n" | xargs -n1 host | awk '{print $4}'`
It looks like $cmd
generates a bunch of host names in a single line. You turn spaces into newlines with the tr
, then run host
on each of lines. For each host
output, you grab the address.
You could do that in a single Perl program:
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;
}
With the backticks in a list context, Perl breaks the output of the command into lines for you. The core modules Socket and Net::hostent come with Perl.
I've used v5.24 for its very nice postfix dereferencing feature, ->@*
, that turns the array reference from addr_list
into a regular list that map
can use.
You need to be careful about whatever you put in $cmd
. I talk about that at length in the "Security" chapter of Mastering Perl. You can also find some stuff in the perlsec documentation.
Upvotes: 3
Reputation: 126742
With the help of the inet_aton
and inet_ntoa
from the Socket
module, you can very simply do the entire thing in Perl, with the exception of $cmd
because you don't tell us what that is
It looks like your $cmd
returns one or more lines of host names, separated by spaces, so I've used an echo
command to emulate it here. I've also used Data::Dump
just to reveal the final contents of @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"]
Upvotes: 2
Reputation: 5927
For similar use perl one liner
perl -nae 'print "$F[3]\n"' input.txt
-n
make the loop for a file
-a
autosplit mode. By default split with space. The output stored into the @F
. So I use third index to print the ip address. In perl index start with 0
Upvotes: 5
Reputation: 53488
Trivially. By default split
works just like awk
. So:
my @arr = split;
print $arr[3]; #note - arrays start at zero.
However, perl generally also works line by line on a filehandle, and a split
gets you stuff you don't want.
You can either:
#!/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
But if you're looking for a single thingummy:
#!/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
We read <DATA>
in a list context, so it returns the whole thing - one element at a time to map.
And then in the map
we split each, and grab element 3
($4
in awk terms).
Upvotes: 5