views:

77

answers:

3

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 considerations 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]

A: 

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" }
}
Eric Strom
sure, but awk can do some things Perl cant' (or not easier)
ghostdog74
@ghostdog..It seems that you like awk more than perl:). Even i do:)
Vijay Sarathi
A: 

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.

Greg Bacon
A: 

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]}'
glenn jackman