如果在命令行上未指定文件,使用STDIN来实现标准Unix行为的惯用方式?

问题描述

如果没有在命令行上给出文件,是否有更优雅的方式来处理来自命令行参数或STDIN的输入?我目前正在这样做:

sub MAIN(*@opt-files,Bool :$debug,... other named options ...) {
    # note that parentheses are mandatory here for some reason
    my $input = @opt-files ?? ([~] .IO.slurp for @opt-files) !! $*IN.slurp;

    ... process $input ...
}

还不错,但是我想知道是否缺少一些更简单的方法吗?

解决方法

我可能会去买multi sub MAIN,就像这样:

multi sub MAIN(Bool :$debug)
{
    process-input($*IN.slurp);
}

multi sub MAIN(*@opt-files,Bool :$debug)
{
    process-input($_.IO.slurp) for @opt-files;
}
,

我可能会做两件事来改变这一点。我分手了?? !!放在不同的行上,我将使用完整的方法链:

sub MAIN(*@opt-files,Bool :$debug,... other named options ...) {
    my $input = @opt-files 
                  ?? @opt-files».IO».slurp.join
                  !! $*IN.slurp;

    ... process $input ...
}

您也可以使用@opt-files.map(*.IO.slurp).join

对其进行映射

编辑:可以在ugexe's answer上构建

sub MAIN(*@opt-files,... other named options ...) {

    # Default to $*IN if not files
    @opt-files ||= '-';

    my $input = @opt-files».IO».slurp.join

    ... process $input ...

}
,

我可能希望起作用的是将@*ARGS设置为签名中的文件名列表。
然后只需使用$*ARGFILES

sub MAIN( *@*ARGS,... other named options ...) {

    my $input = slurp; # implicitly calls $*ARGFILES.slurp()

    ... process $input ...
}

但这不起作用。


在使用之前,您可以通过将Rakudo设置为低级别的空值来将其更新为$*ARGFILES

sub MAIN( *@*ARGS,... other named options ...) {

    { use nqp; $*ARGFILES := nqp::null }

    my $input = slurp;

    ... process $input ...
}

但这使用的实现细节可能会在将来发生变化。


更好的方法是直接自己直接创建IO :: ArgFiles的新实例。

您甚至可以将其存储在$*ARGFILES中。然后slurp自己会吞噬所有文件内容。

sub MAIN( *@opt-files,... other named options ...) {

    my $*ARGFILES = IO::ArgFiles.new( @opt-files || $*IN );

    my $input = slurp;

    ... process $input ...
}

请注意,IO :: ArgFiles只是IO :: CatHandle的一个空子类。 因此,您可以改写IO::CatHandle.new( @opt‑files || $*IN )