perl5 icon indicating copy to clipboard operation
perl5 copied to clipboard

[doc] IPC::Open3 - send STDOUT and STDERR to already open handle

Open Alkorin opened this issue 3 years ago • 6 comments

Where https://perldoc.perl.org/IPC::Open3

Description The documentation state that we can redirect STDIN/STDOUT/STDERR to an already open handle.

    # read from parent STDIN
    # send STDOUT and STDERR to already open handle
    open my $outfile, '>>', 'output.txt' or die "open failed: $!";
    my $pid = open3('<&STDIN', $outfile, undef,
		    'some', 'cmd', 'and', 'args');

But, at least on linux, it doesn't work. This sample code generates an empty file:

#!/usr/bin/perl
use strict;
use warnings;
use IPC::Open3;

open my $outfile, '>', 'out.txt' or die "open failed: $!";

my $pid = open3('<&STDIN', $outfile, '>&STDERR', 'id');
waitpid($pid, 0);

close($outfile);

We can see with strace that perl closes the file descriptor beforing cloning:

...
openat(AT_FDCWD, "out.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
ioctl(3, TCGETS, 0x7ffe44688080)        = -1 ENOTTY (Inappropriate ioctl for device)
lseek(3, 0, SEEK_CUR)                   = 0
fstat(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
close(3)                                = 0
pipe([3, 4])                            = 0
...

It happens here: https://github.com/Perl/perl5/blob/blead/ext/IPC-Open3/lib/IPC/Open3.pm#L242

The code works as expected if we provides manually the file descriptor via >&3

Alkorin avatar Dec 27 '21 17:12 Alkorin

Where https://perldoc.perl.org/IPC::Open3

Description The documentation state that we can redirect STDIN/STDOUT/STDERR to an already open handle.

    # read from parent STDIN
    # send STDOUT and STDERR to already open handle
    open my $outfile, '>>', 'output.txt' or die "open failed: $!";
    my $pid = open3('<&STDIN', $outfile, undef,
		    'some', 'cmd', 'and', 'args');

But, at least on linux, it doesn't work. This sample code generates an empty file:

#!/usr/bin/perl
use strict;
use warnings;
use IPC::Open3;

open my $outfile, '>', 'out.txt' or die "open failed: $!";

In the code sample from the IPC::Open3 docs you quoted above, the second argument to open is >. In your own example above, the second argument to open is >>. Is that difference significant?

my $pid = open3('<&STDIN', $outfile, '>&STDERR', 'id'); waitpid($pid, 0);

close($outfile);


We can see with strace that perl closes the file descriptor beforing cloning:

... openat(AT_FDCWD, "out.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 ioctl(3, TCGETS, 0x7ffe44688080) = -1 ENOTTY (Inappropriate ioctl for device) lseek(3, 0, SEEK_CUR) = 0 fstat(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0 fcntl(3, F_SETFD, FD_CLOEXEC) = 0 close(3) = 0 pipe([3, 4]) = 0 ...


It happens here: https://github.com/Perl/perl5/blob/blead/ext/IPC-Open3/lib/IPC/Open3.pm#L242

The code works as expected if we provides manually the file descriptor via `>&3`

Can you provide a code sample for what you mean by manually providing the file descriptor via >&3?

jkeenan avatar Dec 30 '21 23:12 jkeenan

I did the test with both > and >> it's the same.

3 is the first free file descriptor, a proper code sample would be:

#!/usr/bin/perl
use strict;
use warnings;
use IPC::Open3;

open my $outfile, '>', 'out.txt' or die "open failed: $!";

my $pid = open3('<&STDIN', '>&' . fileno($outfile), '>&STDERR', 'id');
waitpid($pid, 0);

close($outfile);

Alkorin avatar Dec 31 '21 13:12 Alkorin

I did the test with both > and >> it's the same.

3 is the first free file descriptor, a proper code sample would be:

#!/usr/bin/perl
use strict;
use warnings;
use IPC::Open3;

open my $outfile, '>', 'out.txt' or die "open failed: $!";

my $pid = open3('<&STDIN', '>&' . fileno($outfile), '>&STDERR', 'id');
waitpid($pid, 0);

close($outfile);

Could you please file a pull request with that code?

jkeenan avatar Dec 31 '21 13:12 jkeenan

The documentation state that we can redirect STDIN/STDOUT/STDERR to an already open handle.

And you can.

open( local *CHILD_OUT, ">", "outfile.txt" ) or die $!;
my $pid = open3("<&STDIN", ">&CHILD_OUT", undef, ... );

I don't think the approach used in the documentation has ever worked.

ikegami avatar Mar 03 '22 21:03 ikegami

The documentation state that we can redirect STDIN/STDOUT/STDERR to an already open handle.

And you can.

open( local *CHILD_OUT, ">", "outfile.txt" ) or die $!;
my $pid = open3("<&STDIN", ">&CHILD_OUT", undef, ... );

Or if you start with an arbitrary handle,

open( local *CHILD_OUT, ">&=", $fh ) or die $!;
my $pid = open3("<&STDIN", ">&CHILD_OUT", undef, ... );

I avoid IPC::Open3. I recommend IPC::Run.

ikegami avatar Mar 03 '22 21:03 ikegami

I don't think the approach used in the documentation has ever worked.

I've just wasted far too much time due to attempting to follow this example in the IPC::Open3 docs. Couldn't it at least be removed if it doesn't work and has never worked?

ojwb avatar Dec 14 '23 20:12 ojwb