代码之家  ›  专栏  ›  技术社区  ›  Stefan Lasiewski

我如何将PerlOne语句转换为完整的脚本?

  •  17
  • Stefan Lasiewski  · 技术社区  · 14 年前

    我在网上发现了很多PerlOne语句。有时我想将这些一行程序转换成脚本,因为否则我会忘记一行程序的语法。

    例如,我使用以下命令(从 nagios.com ):

    tail -f /var/log/nagios/nagios.log | perl -pe 's/(\d+)/localtime($1)/e'
    

    我想换成这样的:

    tail -f /var/log/nagios/nagios.log | ~/bin/nagiostime.pl
    

    但是,我无法找到将这些东西快速放入脚本的最佳方法。有没有人有一个快速的方法将这些一行程序放入bash或perl脚本中?

    6 回复  |  直到 14 年前
        1
  •  38
  •   brian d foy JRFerguson    14 年前

    您可以通过将任何perl-one行程序传递给 B::Deparse 生成Perl源代码的编译器后端:

    perl -MO=Deparse -pe 's/(\d+)/localtime($1)/e'
    

    输出:

    LINE: while (defined($_ = <ARGV>)) {
        s/(\d+)/localtime($1);/e;
    }
    continue {
        print $_;
    }
    

    与手动解码命令行标志相比,这种方法的优势在于,这正是Perl解释脚本的方式,因此不存在猜测。 B:离开 是核心模块,因此无需安装。

        2
  •  8
  •   brian d foy JRFerguson    14 年前

    看一看 perlrun :

    -P

    使Perl在程序中采用以下循环,这使得它在文件名参数上迭代,有点像sed:

    LINE:
    while (<>) {
        ... # your program goes here
    } continue {
        print or die "-p destination: $!\n";
    }
    

    如果某个参数命名的文件由于某种原因无法打开,Perl会警告您,并转到下一个文件。请注意,这些行是自动打印的。打印过程中发生的错误被视为致命错误。要禁止打印,请使用-n开关。A-P覆盖A-N开关。

    开始块和结束块可以用于捕获隐式循环之前或之后的控件,就像在awk中一样。

    所以,只需取下这段代码,在“你的程序在这里”行插入你的代码,维奥拉,你的脚本准备好了!

    因此,它将是:

    #!/usr/bin/perl -w
    use strict; # or use 5.012 if you've got newer perls
    
    while (<>) {
        s/(\d+)/localtime($1)/e
    } continue {
        print or die "-p destination: $!\n";
    }
    
        3
  •  7
  •   brian d foy JRFerguson    14 年前

    那个人的 真正地 易于存储在脚本中!

    #! /usr/bin/perl -p
    s/(\d+)/localtime($1)/e
    

    这个 -e 选项引入了要执行的Perl代码,您可能会将其视为命令行上的脚本,因此请删除它并将代码粘贴到正文中。离开 -p 在舍邦( #! 行。

    一般来说,在shebang线中最多坚持一个“一束”选项是最安全的。如果你需要更多,你可以把它们的等价物扔到 BEGIN {} 块。

    别忘了 chmod +x ~/bin/nagiostime.pl

    你可以变得更喜欢并嵌入 tail 部分:

    #! /usr/bin/perl -p
    
    BEGIN {
      die "Usage: $0 [ nagios-log ]\n" if @ARGV > 1;
      my $log = @ARGV ? shift : "/var/log/nagios/nagios.log";
      @ARGV = ("tail -f '$log' |");
    }
    
    s/(\d+)/localtime($1)/e
    

    这是因为代码是由 -P 使用Perl的“魔力”(2参数) open 专门处理管道的。

    没有参数,它转换 nagios.log ,但也可以指定其他日志文件, 例如 ,

    $ ~/bin/nagiostime.pl /tmp/other-nagios.log
        4
  •  4
  •   brian d foy JRFerguson    14 年前

    罗伯特有上述“真实”的答案,但这不是很实际。-p开关有点神奇,其他选项甚至更神奇(例如,查看-i标志后面的逻辑)。实际上,我只需要制作一个bash别名/函数来包装OneLiner,而不是将其转换为脚本。

    或者,这里是您的OneLiner脚本::)

    #!/usr/bin/bash
    # takes any number of arguments: the filenames to pipe to the perl filter
    
    tail -f $@ | perl -pe 's/(\d+)/localtime($1)/e'
    
        5
  •  3
  •   brian d foy JRFerguson    14 年前

    如果您想让一行程序转换脚本,甚至可能扩展它,这里有一些很好的答案,但是最简单的方法是:

    #!/usr/bin/perl -p
    s/(\d+)/localtime($1)/e
    

    Perl将识别脚本的hashbang行上的参数,因此您可以继续使用-p执行隐式循环,而不是完全写出循环。

    但是,如果计划使用-w和“use strict;”作为编写较长脚本的起点,那么显式编写循环和使用它是很好的。

        6
  •  3
  •   brian d foy JRFerguson    14 年前
    #!/usr/bin/env perl
    
    while(<>) {
        s/(\d+)/localtime($1)/e;
        print;
    }
    

    while循环和打印是-p自动为您做的。