2017-02-28 17 views
9

Tôi đã chơi xung quanh với shell và cách nó hoạt động khi tôi thay đổi các tệp chuẩn trong chương trình gọi điện. Proc nói:

$ in, $ out và $ err là ba luồng chuẩn của chương trình được khởi chạy và mặc định thành "-", có nghĩa là chúng kế thừa luồng từ quy trình gốc.

Theo như tôi có thể nói, các chương trình bên ngoài không sử dụng cùng một tập tin xử lý:

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

Kết quả cho thấy rằng khi tôi mở /dev/null và gán filehandle của nó để $*OUT, đầu ra từ chương trình hiện tại không hiển thị trong thiết bị đầu cuối (không có đầu ra nào bắt đầu bằng 3.). Tuy nhiên, khi tôi gọi shell, sản lượng tiêu chuẩn của nó đi vào gốc đầu ra tiêu chuẩn:

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 

Tôi không lo lắng về việc làm thế nào để thực hiện điều này. Tôi có thể tạo một đối tượng Proc và chuyển các tệp thủ công cho đối tượng đó.

Có điều gì khác đang xảy ra không?

+1

Mã liên quan trong MoarVM có vẻ là trong [MVM_proc_shell] (https://github.com/MoarVM/MoarVM/blob/7bd72321b0f009178c1931d50c8faae6bf4a25d8/src/io/procops.c#L184). Trên Windows, lần đầu tiên tập lệnh được chạy, nó không thể tìm thấy tệp mà nó vừa tạo.Trong lần chạy thứ hai, tôi quan sát hành vi tương tự (sau khi thay thế '/ dev/null' bằng' NUL'). –

Trả lời

4

Theo mặc định IO :: Xử lý trong $*OUT bị ràng buộc với tệp cấp thấp STDOUT do hệ điều hành cung cấp.

shellrun chỉ cho phép quá trình sinh sản sử dụng tệp STDOUT cấp thấp được cấp cho Perl 6, trừ khi bạn chỉ định khác.

Perl 6 không thay đổi bất cứ điều gì về môi trường bên ngoài cho đến thời điểm trước khi nó sinh ra một quy trình mới.


Điều đơn giản nhất để làm là để cung cấp cho các đối tượng filehandle bạn muốn sử dụng để các shell hoặc run cuộc gọi với một đối số được đặt tên.

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

này kết quả trong

STDERR: run 
STDOUT: shell 

Trong trường hợp đặc biệt của ném đi những dữ liệu đầu ra, :!out hoặc :!err nên được sử dụng để thay thế.

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

Nếu bạn chỉ muốn các dữ liệu bị chặn cho bạn :out:err làm việc đó;

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

Ok, nhưng tài liệu Proc nói rằng shell kế thừa các luồng của quá trình cha mẹ. Có một nơi nào đó trong các tài liệu thảo luận về "Về cơ bản sửa đổi bất kỳ biến ngoại trừ% * ENV trong Perl 6 không có tác dụng bên ngoài."? Đây có phải là một mục tiêu thiết kế hay nó là một vấn đề thực hiện? –

Các vấn đề liên quan