代码之家  ›  专栏  ›  技术社区  ›  Wes

用-p和-f选项调用脚本中的perl进程argv

  •  1
  • Wes  · 技术社区  · 7 年前

    我用-p和-f选项调用了一个Perl脚本。我想在脚本中将命令行参数传递给argv。

    例如, opl.pl 是一个将不以开头的每一行连接起来的脚本 XX 到上一行 XX ''' 作为分隔符,在标记预先存在的 ''' 字符:

    # Usage: perl -pf opl.pl file.txt
    BEGIN {$recmark = @ARGV[0] if $#ARGV; }
    $recmark  = "xx" if (! defined $recmark);
    chomp;
    print "\n" if /$recmark/;
    s/#/\_\_hash\_\_/g;
    $_ .= "#"
    

    当命令行上没有其他参数时,脚本将工作。例如。, perl -pf oplx.pl filexx.txt 具有 filexx.txt :

    xx line #1
    line 2
    line 3
    xx line 4
    line 5
    

    生产(大约):

    xx line __hash__1#line 2#line 3
    xx line 4#line 5
    

    我想使用 perl -pf oplx.pl filexyy.txt yy 具有 fileyy.txt :

    yy line #1
    line 2
    line 3
    yy line 4
    line 5
    

    生产(大约):

    yy line __hash__1#line 2#line 3
    yy line 4#line 5
    

    不幸的是,Perl解析命令行参数 yy 作为文件名,而不是作为参数。

    3 回复  |  直到 7 年前
        1
  •  1
  •   Wes    7 年前

    perlrun(1) 人页:

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

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

    最适当的使用 -p 开关用于一行程序,在该行程序中,依次处理每个文件参数,并将程序的执行结果打印到stdout。

    Perl的尖括号,由 -P 切换,以一个filehandle作为输入,并遍历每一行,直到到达eof:

    while(<$opened_file_handle>) {
        …
    }
    

    然而 ,如果没有传递文件句柄,则尖括号将默认为 @ARGV ,将每个可用参数视为文件名。如果@argv为空, <> 回到标准输入(相当于使用 <STDIN> )

    如果你想传递两个参数 文件名在命令行上,您有两个选择:

    1. 对参数进行排序,使与文件无关的参数排在第一位,如下所示:

      perl -f opt.pl ABC XYZ file1.txt file2.txt
      

    在你的剧本里:

    my $first = shift;  # Modifies @ARGV in-place, placing "ABC" in $first
    my $second = shift; # Same again, this time plucking "XYZ" from @ARGV and putting it in `$second`
    
    1. 或者,使用 Getopt::Long 将非文件名参数作为开关(或“选项”)传递的模块:

      perl -f opt.pl --foo ABC --bar XYZ  file1.txt file2.txt …
      

    以及Perl代码:

    use Getopt::Long;
    my $foo = "";
    my $bar = "";
    GetOptions("foo=s" => \$foo, "bar=s" => \$bar);
    

    使用 GOOPT::长 是在处理文件列表时传递参数的更干净(也是推荐的方法)。

    希望这有帮助!

        2
  •  1
  •   mob    7 年前

    考虑使用一个环境变量作为替代方法来处理命令行参数。

    recmark=yy perl -pf opl.pl file1 file2 ...
    
    BEGIN { $recmark = $ENV{recmark} // "xx" };
    ...
    
        3
  •  1
  •   zdim    7 年前

    这个 -n command switch

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

    LINE:
      while (<>) {
         ...        # your program goes here
      }
    

    哪里 <> filehandle 是特殊的

    输入来自 <> 要么来自标准输入,要么来自命令行中列出的每个文件。

    换句话说,它从命令行上给出的所有文件中读取行。这个 -p 除了它还可以打印 $_ 每次通过。

    这些文件名在 @ARGV variable ,在您的示例中, filexyy.txt yy ,并将其视为文件名。

    一种解决方案:删除所需参数( YY 这里) @ ARGV ,在 BEGIN 块。然后操作 <> 确实只有文件名可以使用。

    这就引出了程序所需接口的问题。如果希望最后在命令行上提供该参数

    my $param;
    BEGIN {
        $param = pop @ARGV;
    }
    

    自从 pop 从数组的后面移除;如果要先给定参数,请使用 shift . 注意你的 $recmark 也必须从 @ ARGV .

    跟踪所有这些都是容易出错的,并且不便于使用和进一步工作。

    最好使用一个好的模块来处理这些参数,比如 Getopt::Long .然后,您可以给它们命名,在需要时轻松地更改接口,并让模块正确检查每个调用。

    还要注意,如果文件名位于 @ ARGV ,这是你之后留下的(或 Getopt::Long )通过选项,您可以处理

    while (<>) { ... }
    

    使用相同的 <> 以上提到。在剧本里这比 -P .

    推荐文章