问题
I was playing around with shell
and how it acts when I change the standard filehandles in the calling program. Proc says:
$in, $out and $err are the three standard streams of the to-be-launched program, and default to "-", which means they inherit the stream from the parent process.
As far as I can tell, the external program doesn't use the same file handles:
#!/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";
The output shows that when I open /dev/null and assign its filehandle to $*OUT
, the output from the current program don't show up in terminal (there's no output starting with 3.
). However, when I call shell
, its standard output goes to the original standard output:
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
I'm not worried about how to make this happen. I can create a Proc
object and pass filehandles to it.
Is there something else going on?
回答1:
By default the IO::Handle that is in $*OUT
is bound to the low-level STDOUT filehandle given by the operating system.
shell
and run
just let the spawned process use the low-level STDOUT file that was given to Perl 6, unless you specify otherwise.
Perl 6 doesn't change anything about the outside environment until the moment before it spawns a new process.
The simplest thing to do is to give the filehandle object you want to use to the shell
or run
call with a named argument.
# 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);
}
This results in
STDERR: run
STDOUT: shell
In the particular case of throwing away the output data, :!out
or :!err
should be used instead.
run $*EXECUTABLE, $p6-name, 'no STDERR', :!err;
STDOUT: no STDERR
If you just want the data to be intercepted for you :out
and :err
do just that;
my $fh = run( $*EXECUTABLE, $p6-name, 'capture', :out ).out;
print 'captured: ',$fh.slurp-rest;
captured: STDOUT capture
来源:https://stackoverflow.com/questions/42505139/does-changing-perl-6s-out-change-standard-output-for-child-processes