2017-02-28 4 views
9

私はshellで遊んでいました。呼び出し元のプログラムで標準のファイルハンドルを変更したときの動作はどうでしたか?彼らは親プロセスからのストリームを継承することを意味する、 - 「」ERR 3つの標準に-発売されるプログラムの流れ、およびデフォルトにしている

は$うちに$および$: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では、スクリプトを初めて実行すると、作成したばかりのファイルが見つかりません。2回目の実行では、( '/ dev/null'を' NUL'に置き換えて)同じ動作を観察します。 –

答えて

4

デフォルトでは、$*OUTにあるIO :: Handleは、オペレーティングシステムによって指定された低レベルのSTDOUTファイルハンドルにバインドされています。

shellrunは、特に指定しない限り、生成されたプロセスにPerl 6に与えられた低レベルのSTDOUTファイルを使用させます。

Perl 6は、新しいプロセスを生成するまで、外部環境について何も変更しません。


最も簡単な方法は、あなたが名前付き引数とshellまたはrun通話に使用するファイルハンドルオブジェクトを与えることです。出力データを捨てるの特定の場合には

STDERR: run 
STDOUT: shell 

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

この結果は、:!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 docsはシェルが親プロセスのストリームを継承していると言っています。 "Perl 6で%* ENV以外の変数を基本的に変更すると、外的な影響はありません"という議論のどこかにありますか?これは設計目標ですか、実装上の問題ですか? –

関連する問題