2017-02-28 25 views
9

我正在玩shell以及它如何改變調用程序中的標準文件句柄。 Proc說:

在$,$出和$犯錯是要被啓動的程序的三個標準流,並且默認爲「 - 」,這意味着他們繼承父進程流。

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

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

輸出表明,當我打開的/ 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 

我並不擔心如何做到這一點。我可以創建一個Proc對象並將文件句柄傳遞給它。

還有別的事情嗎?

+1

在MoarVM相關的代碼似乎是在[MVM_proc_shell](https://github.com/MoarVM/MoarVM/blob/7bd72321b0f009178c1931d50c8faae6bf4a25d8/src/io/procops.c#L184)。在Windows上,第一次運行腳本時,它無法找到剛創建的文件。在第二次運行時,我觀察到相同的行爲(在用'NUL'替換'/ dev/null'後)。 –

回答

4

默認情況下,$*OUT中的IO :: Handle綁定到操作系統給出的低級STDOUT文件句柄。

shellrun只是讓產生的進程使用給予Perl 6的低級STDOUT文件,除非您另有指定。

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); 
} 

這導致

STDERR: run 
STDOUT: shell 

在扔掉的輸出數據的特定情況下,:!out:!err應改爲使用。

run $*EXECUTABLE, $p6-name, 'no STDERR', :!err; 
STDOUT: no STDERR 

如果你只是想攔截你:out數據和:err做到這一點;

my $fh = run($*EXECUTABLE, $p6-name, 'capture', :out).out; 
print 'captured: ',$fh.slurp-rest; 
captured: STDOUT capture 
+3

好的,但Proc文檔說shell繼承父進程的流。在文檔中是否有某處討論「基本上修改除%以外的任何變量*在Perl 6中,ENV沒有外部影響」?這是設計目標還是實施問題? –