【问题标题】:How can I convert Perl one-liners into complete scripts?如何将 Perl 单行代码转换为完整的脚本?
【发布时间】:2010-05-12 20:30:21
【问题描述】:

我在网上找到了很多 Perl 单行代码。有时我想将这些单行代码转换成脚本,否则我会忘记单行代码的语法。

例如,我正在使用以下命令(来自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 脚本中?

【问题讨论】:

  • 备案:请注意,我在最初的帖子中有错字。我说的是“localtime”,而我真正的意思是“localtime($1)”。因此,在阅读以下任何答案时,请确保使用 localtime($1)。
  • 实际上最好在 perl 脚本中实现tail -f 而不是通过管道传递给它。考虑以下代码:tail -f some_file | perl -e exit,与预期相反,它永远不会返回。

标签: perl command-line


【解决方案1】:

您可以将任何 Perl 单行代码通过生成 Perl 源代码的B::Deparse 编译器后端传递给完整的脚本:

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

输出:

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

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

【讨论】:

  • 哇,这里有这么多好的和正确的答案。由于“B::Deparse”提示,这篇文章获胜。第 1 步是将单行代码迁移到脚本。第 2 步通常是扩展该脚本,这种“B::Deparse”方法确保我们从一些好的语法开始。
【解决方案2】:

看看perlrun

-p

导致 Perl 假设您的程序周围有以下循环,这使得它迭代文件名参数有点像 sed:

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

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

BEGIN 和 END 块可用于在隐式循环之前或之后捕获控制,就像在 awk 中一样。

所以,只需获取这段代码,在“# your program going here”行插入你的代码,viola,你的脚本就准备好了!

因此,它将是:

#!/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】:

    那个真的很容易存储在脚本中!

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

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

    一般来说,在 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】:

      罗伯特在上面有“真实”的答案,但不是很实用。 -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】:

        如果您想保留单行转换脚本甚至可能对其进行扩展,这里有一些很好的答案,但可能可行的最简单的事情就是:

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

        Perl 会识别脚本的 hashbang 行上的参数,所以不用完整地写出循环,你可以继续使用 -p 执行隐式循环。

        但是显式编写循环并使用 -w 和 "use strict;"如果计划将其用作编写更长脚本的起点,那就太好了。

        【讨论】:

          【解决方案6】:
          #!/usr/bin/env perl
          
          while(<>) {
              s/(\d+)/localtime($1)/e;
              print;
          }
          

          while 循环和打印是 -p 自动为您执行的操作。

          【讨论】:

            猜你喜欢
            • 2020-01-18
            • 1970-01-01
            • 1970-01-01
            • 2020-08-24
            • 1970-01-01
            • 2011-01-09
            • 2019-06-23
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多