【问题标题】:How to convert this shell script to a platform independent Perl script?如何将此 shell 脚本转换为独立于平台的 Perl 脚本?
【发布时间】:2010-08-24 20:37:18
【问题描述】:

我有一个类似这样的 cshell 脚本:

`netstat -ap | & grep tcp | grep myprocess | awk '{print $4}' | awk 'BEGIN { FS = :"}{print $2}'`

这就是它的工作原理

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

我需要使用 Perl 使其尽可能便携。我认为没有netstatgrep 的行为就无法保证可移植性,所以我会尽量确保它们在目标系统上得到支持。

我在找

  • 要使 Perl 脚本具有可移植性,需要牢记哪些一般注意事项?
  • 如何在 Perl 中复制 awk 行为?
  • 我也可以在 Perl 中复制grep 的行为吗?这样做是否可取(只有在 Perl 的 grep 有任何优势时我才会这样做)?

[我在这里针对所有流行的 Windows 和 Linux 版本]

【问题讨论】:

  • @gbacon: 不是 PERL = Practical Extraction Report Language
  • => 那是一个反义词,原名不代表任何东西,语言的专有名称是Perl,解释器的名称是perl
  • awk '{print $4}' | awk 'BEGIN { FS = ":"}{print $2}' 可以替换为单个 awk 语句 awk '{split($4,:,a);print a[2]}'

标签: perl shell awk grep portability


【解决方案1】:

有一个netstat for Windows,但它的-p 不能满足您的要求。

至于其他功能,你可以使用

#! /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";
}

对于netstat 输出的每一行,它是一个 TCP 连接并与命令行中命名的程序相关联,获取本地地址(第 4 列),删除字符串中最后一个冒号的所有内容——它应该离开端口— 并打印结果。

【讨论】:

    【解决方案2】:

    一般来说,perl 可以做任何awkgrep 可以做的事情,如果跨平台操作很重要,将所有逻辑保存在一个程序中会有所帮助(不依赖外壳)。

    这样的事情可能对你有用:

    perl -ne 'if (/tcp/ and /myprocess/) { (split /\s+/)[3] =~ /(\d+)/; print $1 }'
    

    未经测试,但应该很接近。此单行程序需要标准输入上的 netstat 输入。

    您还可以在 Perl 中执行以下操作:

    #!/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" }
    }
    

    【讨论】:

    • 当然,但是 awk 可以做一些 Perl 无法做到的事情(或者更简单)
    • @ghostdog..看来你更喜欢 awk 而不是 perl:)。即使我这样做:)
    • @ghostdog74 awk 太棒了:)
    【解决方案3】:

    似乎最不可移植的是 netstat 调用,但是:

    netstat -ap | perl -lane '
        next unless /tcp/ and /myprocess/;  # this is the "grep" part
        print((split /:/, $F[3])[-1]); # this is the "awk" part
    '
    

    或者,坚持使用 awk,它可以轻松完成 grep 的工作:

    netstat -ap | awk '/tcp/ && /myprocess/ {split($4, a, /:/); print a[2]}'
    

    将“myprocess”作为变量传递到 awk 脚本中:

    netstat -ap | awk -v proc="myprocess" '/tcp/ && $0 ~ proc {split($4, a, /:/); print a[2]}'
    

    【讨论】:

      【解决方案4】:

      要在 perl 中复制 awk 脚本行为,有一个命令 a2p 应该随大多数 perl 发行版一起提供。

      perl 支持开箱即用的模式匹配,无疑比 grep 更强大

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-08-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多