改变Perl 6的$*OUT是否会改变子进程的标准输出?

bri*_*foy 11 shell stdout perl6 raku

shell当我在调用程序中更改标准文件句柄时,我正在玩它以及它是如何动作的.Proc说:

$ in,$ out和$ err是待启动程序的三个标准流,默认为" - ",这意味着它们从父进程继承流.

据我所知,外部程序不使用相同的文件句柄:

#!/Applications/Rakudo/bin/perl6

#`(
    make an external Perl 6 program the outputs to standard handles
    )
my $p6-name = 'in-out.p6'.IO;
#END try $p6-name.unlink; # why does this cause it to fail?
my $p6-fh = open $p6-name, :w;
die "Could not open $p6-name" unless ?$p6-fh;
$p6-fh.put: Q:to/END/;
    #!/Applications/Rakudo/bin/perl6

    $*ERR.say( qq/\t$*PROGRAM: This goes to standard error/ );
    $*OUT.say( qq/\t$*PROGRAM: This goes to standard output/ );
    END
$p6-fh.close;
say $p6-name.e ?? 'File is there' !! 'File is not there';
die "$p6-name does not exist" unless $p6-name.e;

{
#`(
    Start with some messages to show that we can output to
    the standard filehandles.
    )
$*OUT.put: "1. standard output before doing anything weird";
$*ERR.put: "2. standard error before doing anything weird";
shell( "perl6 $p6-name" ).so;
}

{
#`(
    This block assigns a new filehandle to $*OUT and prints a
    message to it. I expect that message to not show up in the
    terminal.

    It then calls run-them to fire off the external process. It
    should inherit the same standard out and its standard out
    messages should not show up. But, they do.
    )
temp $*OUT = open '/dev/null', :w;
$*OUT.put: "3. temp redefine standard output before this message";
shell( "perl6 $p6-name" ).so;
}

$*OUT.put: "4. everything should be back to normal";
Run Code Online (Sandbox Code Playgroud)

输出显示当我打开/ dev/null并将其文件句柄分配给时$*OUT,当前程序的输出不会显示在终端中(没有输出开头3.).但是,当我打电话时shell,它的标准输出转到原始标准输出:

File is there
1. standard output before doing anything weird
2. standard error before doing anything weird
    in-out.p6: This goes to standard error
    in-out.p6: This goes to standard output
    in-out.p6: This goes to standard error
    in-out.p6: This goes to standard output
4. everything should be back to normal
Run Code Online (Sandbox Code Playgroud)

我并不担心如何实现这一目标.我可以创建一个Proc对象并将文件句柄传递给它.

还有其他事情发生吗?

Bra*_*ert 6

默认情况下,处于的IO :: Handle $*OUT绑定到操作系统给出的低级STDOUT文件句柄.

shellrun只是让衍生的进程使用给予了Perl 6的,除非另行指定低级别的标准输出文件.

Perl 6在产生新进程之前不会改变外部环境.


最简单的方法是将要使用的文件句柄对象赋予shellrun使用命名参数调用.

# no testing for failure because the default is to throw an error anyway

my $p6-name = 'in-out.p6'.IO;
END $p6-name.unlink;

$p6-name.spurt(Q'put "STDOUT: @*ARGS[0]";note "STDERR: @*ARGS[0]"');

run $*EXECUTABLE, $p6-name, 'run', :out(open '/dev/null', :w);

{
  temp $*OUT = open '/dev/null', :w;
  shell "'$*EXECUTABLE' '$p6-name' 'shell'", :err($*OUT);
}
Run Code Online (Sandbox Code Playgroud)

这导致了

STDERR: run
STDOUT: shell
Run Code Online (Sandbox Code Playgroud)

在丢弃输出数据的特定情况下,:!out:!err应该使用.

run $*EXECUTABLE, $p6-name, 'no STDERR', :!err;
Run Code Online (Sandbox Code Playgroud)
STDOUT: no STDERR
Run Code Online (Sandbox Code Playgroud)

如果你只是希望为你拦截数据:out:err做到这一点;

my $fh = run( $*EXECUTABLE, $p6-name, 'capture', :out ).out;
print 'captured: ',$fh.slurp-rest;
Run Code Online (Sandbox Code Playgroud)
captured: STDOUT capture
Run Code Online (Sandbox Code Playgroud)

  • 好的,但是Proc文档说shell继承了父进程的流.是否在文档中的某处讨论"基本上修改除Perl 6中的%*ENV之外的任何变量都没有外部影响."?这是设计目标还是实施问题? (3认同)