如果命令行上没有指定文件,使用 STDIN 实现标准 Unix 行为的惯用方法?
Idiomatic way to implement standard Unix behaviour of using STDIN if no files are specified on the command line?
是否有更优雅的方式来处理来自命令行参数或 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, Bool :$debug, ... 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, Bool :$debug, ... other named options ...) {
my $input = slurp; # implicitly calls $*ARGFILES.slurp()
... process $input ...
}
不过没用。
您可以让 Rakudo 更新 $*ARGFILES
,方法是在您使用它之前用 low-level null 将其清零。
sub MAIN( *@*ARGS, Bool :$debug, ... other named options ...) {
{ use nqp; $*ARGFILES := nqp::null }
my $input = slurp;
... process $input ...
}
但这是使用将来可能会更改的实现细节。
更好的方法是自己直接创建 IO::ArgFiles 的新实例。
您甚至可以将其存储在 $*ARGFILES
中。然后 slurp
自己会吞噬所有文件内容。
sub MAIN( *@opt-files, Bool :$debug, ... 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 )
代替。
是否有更优雅的方式来处理来自命令行参数或 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, Bool :$debug, ... 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, Bool :$debug, ... other named options ...) {
my $input = slurp; # implicitly calls $*ARGFILES.slurp()
... process $input ...
}
不过没用。
您可以让 Rakudo 更新 $*ARGFILES
,方法是在您使用它之前用 low-level null 将其清零。
sub MAIN( *@*ARGS, Bool :$debug, ... other named options ...) {
{ use nqp; $*ARGFILES := nqp::null }
my $input = slurp;
... process $input ...
}
但这是使用将来可能会更改的实现细节。
更好的方法是自己直接创建 IO::ArgFiles 的新实例。
您甚至可以将其存储在 $*ARGFILES
中。然后 slurp
自己会吞噬所有文件内容。
sub MAIN( *@opt-files, Bool :$debug, ... 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 )
代替。