How to convert this shell script to a platform independent Perl script?
I have a cshell script that is something like this:
`netstat -ap | & grep tcp | grep myprocess | awk '{print $4}' | awk 'BEGIN { FS = :"}{print $2}'`
This is how it works
1.
$ netstat -ap | & grep tcp | grep myprocess
tcp 0 0 *:1234 *:* LISTEN 8888/myprocess
2.
$ netstat -ap | & grep tcp | grep myprocess | awk '{print $4}'
*:1234
3.
$ netstat -ap | & grep tcp | grep myprocess | awk '{print $4}' | awk 'BEGIN { FS = ":"}{print $2}'`
1234
I need to make this as portable as possible using Perl. I think portability can't be guaranteed without the behaviour of netstat
and grep
, so I will try to make sure that they are supported on the target systems.
I am looking for
- Any general consid开发者_C百科erations to keep in mind to make the Perl script portable?
- How can I replicate the
awk
behaviour in Perl? - Can I also replicate the behavior of
grep
in Perl? Is that advisable (I'll do it only if Perl's grep has any advantages)?
[I am targeting all prevalent Windows and Linux versions here]
There's a netstat
for Windows, but its -p
doesn't do what you want.
As for the rest of the functionality, you could use
#! /usr/bin/perl
use warnings;
use strict;
die "Usage: $0 program\n" unless @ARGV == 1;
# e.g., ... 1234/myprocess
my $prog = qr< / \Q$ARGV[0]\E $ >x; # / fix SO highlighting
no warnings 'exec';
open my $netstat, "-|", "netstat", "-ap"
or die "$0: cannot start netstat: $!";
while (<$netstat>) {
my @f = split;
next unless $f[0] eq "tcp" && $f[-1] =~ /$prog/;
(my $local = $f[3]) =~ s/^.*://;
print $local, "\n";
}
For each line of netstat
output that's a TCP connection and associated with the program named on the command line, grab the local address (column 4), remove everything through the last colon in the string—which should leave the port—and print the result.
In general, perl
can do anything that awk
or grep
can do, and if cross platform operation is important, keeping all of your logic in one program can help (no reliance on the shell).
Something like this might work for you:
perl -ne 'if (/tcp/ and /myprocess/) { (split /\s+/)[3] =~ /(\d+)/; print $1 }'
Untested, but it should be close. This one-liner expects the netstat input on stdin.
You can also do everything in Perl as follows:
#!/usr/bin/env perl
use warnings;
use strict;
open my $netstat, '-|', 'netstat -ap';
while (<$netstat>) {
next unless /tcp/ and /myprocess/;
my @fields = split /\s+/;
if ($fields[3] =~ /(\d+)/) { print "$1\n" }
}
Seems the most non-portable thing is the netstat call, but:
netstat -ap | perl -lane '
next unless /tcp/ and /myprocess/; # this is the "grep" part
print((split /:/, $F[3])[-1]); # this is the "awk" part
'
or, stick with awk, which can easily do what grep does:
netstat -ap | awk '/tcp/ && /myprocess/ {split($4, a, /:/); print a[2]}'
To pass "myprocess" as a variable into the awk script:
netstat -ap | awk -v proc="myprocess" '/tcp/ && $0 ~ proc {split($4, a, /:/); print a[2]}'
To replicate the awk script behavior in perl, there is a command a2p
that should come with most perl distributions.
perl supports pattern matching out of the box, and its undoubtedly more powerful than grep
精彩评论