如何将Perl单行转换为完整脚本?

时间:2010-05-12 20:30:22

标签: perl command-line

我在网上发现了很多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脚本中?

6 个答案:

答案 0 :(得分:38)

您可以将任何Perl one-liner转换为完整脚本,方法是将其传递给生成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是核心模块,因此无需安装。

答案 1 :(得分:8)

看看perlrun

  

-p

     

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

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

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

     

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

所以,只需要获取这段代码,将代码插入“#your program goes here”行,并且中提琴,你的脚本就准备好了!

因此,它将是:

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

答案 2 :(得分:7)

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

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

答案 3 :(得分: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'

答案 4 :(得分:3)

#!/usr/bin/env perl

while(<>) {
    s/(\d+)/localtime($1)/e;
    print;
}

while循环和print是-p自动为你做的。

答案 5 :(得分:3)

如果你想保留一行翻译脚本并且甚至可能扩展它,那么这里有一些很好的答案,但最简单的事情可能就是:

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

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

但是明确地编写循环并使用-w和“use strict;”如果计划将它作为编写更长脚本的起点,那就好了。