New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IPC::Open2 and IPC::Open3 documentation updates #16688
Comments
From @Grinnz[Perl] IPC::Open2 and IPC::Open3 docs contain some out of date practices * Remove direct usage of bareword filehandles and use lexical filehandles -Dan |
From @GrinnzPatch is attached. |
From @Grinnzipc_open23_docs.patchdiff --git a/ext/IPC-Open3/lib/IPC/Open2.pm b/ext/IPC-Open3/lib/IPC/Open2.pm
index 9e27144571..9c70e5b455 100644
--- a/ext/IPC-Open3/lib/IPC/Open2.pm
+++ b/ext/IPC-Open3/lib/IPC/Open2.pm
@@ -18,38 +18,41 @@ IPC::Open2 - open a process for both reading and writing using open2()
use IPC::Open2;
- $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'some cmd and args');
- # or without using the shell
- $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'some', 'cmd', 'and', 'args');
+ my $pid = open2(my $chld_out, my $chld_in, 'some', 'cmd', 'and', 'args');
+ # or passing the command through the shell
+ my $pid = open2(my $chld_out, my $chld_in, 'some cmd and args');
- # or with handle autovivification
- my($chld_out, $chld_in);
- $pid = open2($chld_out, $chld_in, 'some cmd and args');
- # or without using the shell
- $pid = open2($chld_out, $chld_in, 'some', 'cmd', 'and', 'args');
+ # read from parent STDIN and write to already open handle
+ open my $outfile, '>', 'outfile.txt' or die "open failed: $!";
+ my $pid = open2($outfile, '<&STDIN', 'some', 'cmd', 'and', 'args');
+ # read from already open handle and write to parent STDOUT
+ open my $infile, '<', 'infile.txt' or die "open failed: $!";
+ my $pid = open2('>&STDOUT', $infile, 'some', 'cmd', 'and', 'args');
+
+ # reap zombie and retrieve exit status
waitpid( $pid, 0 );
my $child_exit_status = $? >> 8;
=head1 DESCRIPTION
-The open2() function runs the given $cmd and connects $chld_out for
+The open2() function runs the given command and connects $chld_out for
reading and $chld_in for writing. It's what you think should work
when you try
- $pid = open(HANDLE, "|cmd args|");
+ my $pid = open(my $fh, "|cmd args|");
-The write filehandle will have autoflush turned on.
+The $chld_in filehandle will have autoflush turned on.
If $chld_out is a string (that is, a bareword filehandle rather than a glob
or a reference) and it begins with C<< >& >>, then the child will send output
directly to that file handle. If $chld_in is a string that begins with
C<< <& >>, then $chld_in will be closed in the parent, and the child will
-read from it directly. In both cases, there will be a dup(2) instead of a
-pipe(2) made.
+read from it directly. In both cases, there will be a L<dup(2)> instead of a
+L<pipe(2)> made.
-If either reader or writer is the null string, this will be replaced
-by an autogenerated filehandle. If so, you must pass a valid lvalue
+If either reader or writer is the empty string or undefined, this will be
+replaced by an autogenerated filehandle. If so, you must pass a valid lvalue
in the parameter slot so it can be overwritten in the caller, or
an exception will be raised.
@@ -66,10 +69,10 @@ Failing to do this can result in an accumulation of defunct or "zombie"
processes. See L<perlfunc/waitpid> for more information.
This whole affair is quite dangerous, as you may block forever. It
-assumes it's going to talk to something like B<bc>, both writing
+assumes it's going to talk to something like L<bc(1)>, both writing
to it and reading from it. This is presumably safe because you
-"know" that commands like B<bc> will read a line at a time and
-output a line at a time. Programs like B<sort> that read their
+"know" that commands like L<bc(1)> will read a line at a time and
+output a line at a time. Programs like L<sort(1)> that read their
entire input stream first, however, are quite apt to cause deadlock.
The big problem with this approach is that if you don't have control
@@ -77,8 +80,8 @@ over source code being run in the child process, you can't control
what it does with pipe buffering. Thus you can't just open a pipe to
C<cat -v> and continually read and write a line from it.
-The IO::Pty and Expect modules from CPAN can help with this, as they
-provide a real tty (well, a pseudo-tty, actually), which gets you
+The L<IO::Pty> and L<Expect> modules from CPAN can help with this, as
+they provide a real tty (well, a pseudo-tty, actually), which gets you
back to line buffering in the invoked command again.
=head1 WARNING
diff --git a/ext/IPC-Open3/lib/IPC/Open3.pm b/ext/IPC-Open3/lib/IPC/Open3.pm
index e5924a30a6..58b92b8948 100644
--- a/ext/IPC-Open3/lib/IPC/Open3.pm
+++ b/ext/IPC-Open3/lib/IPC/Open3.pm
@@ -19,37 +19,47 @@ IPC::Open3 - open a process for reading, writing, and error handling using open3
=head1 SYNOPSIS
- $pid = open3(\*CHLD_IN, \*CHLD_OUT, \*CHLD_ERR,
- 'some cmd and args', 'optarg', ...);
-
- my($wtr, $rdr, $err);
- use Symbol 'gensym'; $err = gensym;
- $pid = open3($wtr, $rdr, $err,
- 'some cmd and args', 'optarg', ...);
-
+ use Symbol 'gensym'; # vivify a separate handle for STDERR
+ my $pid = open3(my $chld_in, my $chld_out, my $chld_err = gensym,
+ 'some', 'cmd', 'and', 'args');
+ # or pass the command through the shell
+ my $pid = open3(my $chld_in, my $chld_out, my $chld_err = gensym,
+ 'some cmd and args');
+
+ # 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');
+
+ # pass command through the shell, write to parent STDOUT and STDERR
+ my $pid = open3(my $chld_in, '>&STDOUT', '>&STDERR',
+ 'some', 'cmd', 'and', 'args');
+
+ # reap zombie and retrieve exit status
waitpid( $pid, 0 );
my $child_exit_status = $? >> 8;
=head1 DESCRIPTION
-Extremely similar to open2(), open3() spawns the given $cmd and
-connects CHLD_OUT for reading from the child, CHLD_IN for writing to
-the child, and CHLD_ERR for errors. If CHLD_ERR is false, or the
-same file descriptor as CHLD_OUT, then STDOUT and STDERR of the child
-are on the same filehandle (this means that an autovivified lexical
-cannot be used for the STDERR filehandle, see SYNOPSIS). The CHLD_IN
+Extremely similar to open2(), open3() spawns the given command and
+connects $chld_out for reading from the child, $chld_in for writing to
+the child, and $chld_err for errors. If $chld_err is false, or the
+same file descriptor as $chld_out, then STDOUT and STDERR of the child
+are on the same filehandle. This means that an autovivified lexical
+cannot be used for the STDERR filehandle, but gensym from L<Symbol> can
+be used to vivify a new glob reference, see L</SYNOPSIS>. The $chld_in
will have autoflush turned on.
-If CHLD_IN begins with C<< <& >>, then CHLD_IN will be closed in the
-parent, and the child will read from it directly. If CHLD_OUT or
-CHLD_ERR begins with C<< >& >>, then the child will send output
-directly to that filehandle. In both cases, there will be a dup(2)
-instead of a pipe(2) made.
+If $chld_in begins with C<< <& >>, then $chld_in will be closed in the
+parent, and the child will read from it directly. If $chld_out or
+$chld_err begins with C<< >& >>, then the child will send output
+directly to that filehandle. In both cases, there will be a L<dup(2)>
+instead of a L<pipe(2)> made.
-If either reader or writer is the null string, this will be replaced
-by an autogenerated filehandle. If so, you must pass a valid lvalue
-in the parameter slot so it can be overwritten in the caller, or
-an exception will be raised.
+If either reader or writer is the empty string or undefined, this will
+be replaced by an autogenerated filehandle. If so, you must pass a
+valid lvalue in the parameter slot so it can be overwritten in the
+caller, or an exception will be raised.
The filehandles may also be integers, in which case they are understood
as file descriptors.
@@ -57,15 +67,15 @@ as file descriptors.
open3() returns the process ID of the child process. It doesn't return on
failure: it just raises an exception matching C</^open3:/>. However,
C<exec> failures in the child (such as no such file or permission denied),
-are just reported to CHLD_ERR under Windows and OS/2, as it is not possible
+are just reported to $chld_err under Windows and OS/2, as it is not possible
to trap them.
-If the child process dies for any reason, the next write to CHLD_IN is
+If the child process dies for any reason, the next write to $chld_in is
likely to generate a SIGPIPE in the parent, which is fatal by default.
So you may wish to handle this signal.
Note if you specify C<-> as the command, in an analogous fashion to
-C<open(FOO, "-|")> the child process will just be the forked Perl
+C<open(my $fh, "-|")> the child process will just be the forked Perl
process rather than an external command. This feature isn't yet
supported on Win32 platforms.
@@ -78,14 +88,14 @@ processes. See L<perlfunc/waitpid> for more information.
If you try to read from the child's stdout writer and their stderr
writer, you'll have problems with blocking, which means you'll want
-to use select() or the IO::Select, which means you'd best use
+to use select() or L<IO::Select>, which means you'd best use
sysread() instead of readline() for normal stuff.
This is very dangerous, as you may block forever. It assumes it's
-going to talk to something like B<bc>, both writing to it and reading
+going to talk to something like L<bc(1)>, both writing to it and reading
from it. This is presumably safe because you "know" that commands
-like B<bc> will read a line at a time and output a line at a time.
-Programs like B<sort> that read their entire input stream first,
+like L<bc(1)> will read a line at a time and output a line at a time.
+Programs like L<sort(1)> that read their entire input stream first,
however, are quite apt to cause deadlock.
The big problem with this approach is that if you don't have control
|
From @GrinnzThere was a mistake in a synopsis comment. Fixed patch attached. |
From @Grinnzipc_open23_docs.patchdiff --git a/ext/IPC-Open3/lib/IPC/Open2.pm b/ext/IPC-Open3/lib/IPC/Open2.pm
index 9e27144571..9c70e5b455 100644
--- a/ext/IPC-Open3/lib/IPC/Open2.pm
+++ b/ext/IPC-Open3/lib/IPC/Open2.pm
@@ -18,38 +18,41 @@ IPC::Open2 - open a process for both reading and writing using open2()
use IPC::Open2;
- $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'some cmd and args');
- # or without using the shell
- $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'some', 'cmd', 'and', 'args');
+ my $pid = open2(my $chld_out, my $chld_in, 'some', 'cmd', 'and', 'args');
+ # or passing the command through the shell
+ my $pid = open2(my $chld_out, my $chld_in, 'some cmd and args');
- # or with handle autovivification
- my($chld_out, $chld_in);
- $pid = open2($chld_out, $chld_in, 'some cmd and args');
- # or without using the shell
- $pid = open2($chld_out, $chld_in, 'some', 'cmd', 'and', 'args');
+ # read from parent STDIN and write to already open handle
+ open my $outfile, '>', 'outfile.txt' or die "open failed: $!";
+ my $pid = open2($outfile, '<&STDIN', 'some', 'cmd', 'and', 'args');
+ # read from already open handle and write to parent STDOUT
+ open my $infile, '<', 'infile.txt' or die "open failed: $!";
+ my $pid = open2('>&STDOUT', $infile, 'some', 'cmd', 'and', 'args');
+
+ # reap zombie and retrieve exit status
waitpid( $pid, 0 );
my $child_exit_status = $? >> 8;
=head1 DESCRIPTION
-The open2() function runs the given $cmd and connects $chld_out for
+The open2() function runs the given command and connects $chld_out for
reading and $chld_in for writing. It's what you think should work
when you try
- $pid = open(HANDLE, "|cmd args|");
+ my $pid = open(my $fh, "|cmd args|");
-The write filehandle will have autoflush turned on.
+The $chld_in filehandle will have autoflush turned on.
If $chld_out is a string (that is, a bareword filehandle rather than a glob
or a reference) and it begins with C<< >& >>, then the child will send output
directly to that file handle. If $chld_in is a string that begins with
C<< <& >>, then $chld_in will be closed in the parent, and the child will
-read from it directly. In both cases, there will be a dup(2) instead of a
-pipe(2) made.
+read from it directly. In both cases, there will be a L<dup(2)> instead of a
+L<pipe(2)> made.
-If either reader or writer is the null string, this will be replaced
-by an autogenerated filehandle. If so, you must pass a valid lvalue
+If either reader or writer is the empty string or undefined, this will be
+replaced by an autogenerated filehandle. If so, you must pass a valid lvalue
in the parameter slot so it can be overwritten in the caller, or
an exception will be raised.
@@ -66,10 +69,10 @@ Failing to do this can result in an accumulation of defunct or "zombie"
processes. See L<perlfunc/waitpid> for more information.
This whole affair is quite dangerous, as you may block forever. It
-assumes it's going to talk to something like B<bc>, both writing
+assumes it's going to talk to something like L<bc(1)>, both writing
to it and reading from it. This is presumably safe because you
-"know" that commands like B<bc> will read a line at a time and
-output a line at a time. Programs like B<sort> that read their
+"know" that commands like L<bc(1)> will read a line at a time and
+output a line at a time. Programs like L<sort(1)> that read their
entire input stream first, however, are quite apt to cause deadlock.
The big problem with this approach is that if you don't have control
@@ -77,8 +80,8 @@ over source code being run in the child process, you can't control
what it does with pipe buffering. Thus you can't just open a pipe to
C<cat -v> and continually read and write a line from it.
-The IO::Pty and Expect modules from CPAN can help with this, as they
-provide a real tty (well, a pseudo-tty, actually), which gets you
+The L<IO::Pty> and L<Expect> modules from CPAN can help with this, as
+they provide a real tty (well, a pseudo-tty, actually), which gets you
back to line buffering in the invoked command again.
=head1 WARNING
diff --git a/ext/IPC-Open3/lib/IPC/Open3.pm b/ext/IPC-Open3/lib/IPC/Open3.pm
index e5924a30a6..58b92b8948 100644
--- a/ext/IPC-Open3/lib/IPC/Open3.pm
+++ b/ext/IPC-Open3/lib/IPC/Open3.pm
@@ -19,37 +19,47 @@ IPC::Open3 - open a process for reading, writing, and error handling using open3
=head1 SYNOPSIS
- $pid = open3(\*CHLD_IN, \*CHLD_OUT, \*CHLD_ERR,
- 'some cmd and args', 'optarg', ...);
-
- my($wtr, $rdr, $err);
- use Symbol 'gensym'; $err = gensym;
- $pid = open3($wtr, $rdr, $err,
- 'some cmd and args', 'optarg', ...);
-
+ use Symbol 'gensym'; # vivify a separate handle for STDERR
+ my $pid = open3(my $chld_in, my $chld_out, my $chld_err = gensym,
+ 'some', 'cmd', 'and', 'args');
+ # or pass the command through the shell
+ my $pid = open3(my $chld_in, my $chld_out, my $chld_err = gensym,
+ 'some cmd and args');
+
+ # 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');
+
+ # pass command through the shell, write to parent STDOUT and STDERR
+ my $pid = open3(my $chld_in, '>&STDOUT', '>&STDERR',
+ 'some', 'cmd', 'and', 'args');
+
+ # reap zombie and retrieve exit status
waitpid( $pid, 0 );
my $child_exit_status = $? >> 8;
=head1 DESCRIPTION
-Extremely similar to open2(), open3() spawns the given $cmd and
-connects CHLD_OUT for reading from the child, CHLD_IN for writing to
-the child, and CHLD_ERR for errors. If CHLD_ERR is false, or the
-same file descriptor as CHLD_OUT, then STDOUT and STDERR of the child
-are on the same filehandle (this means that an autovivified lexical
-cannot be used for the STDERR filehandle, see SYNOPSIS). The CHLD_IN
+Extremely similar to open2(), open3() spawns the given command and
+connects $chld_out for reading from the child, $chld_in for writing to
+the child, and $chld_err for errors. If $chld_err is false, or the
+same file descriptor as $chld_out, then STDOUT and STDERR of the child
+are on the same filehandle. This means that an autovivified lexical
+cannot be used for the STDERR filehandle, but gensym from L<Symbol> can
+be used to vivify a new glob reference, see L</SYNOPSIS>. The $chld_in
will have autoflush turned on.
-If CHLD_IN begins with C<< <& >>, then CHLD_IN will be closed in the
-parent, and the child will read from it directly. If CHLD_OUT or
-CHLD_ERR begins with C<< >& >>, then the child will send output
-directly to that filehandle. In both cases, there will be a dup(2)
-instead of a pipe(2) made.
+If $chld_in begins with C<< <& >>, then $chld_in will be closed in the
+parent, and the child will read from it directly. If $chld_out or
+$chld_err begins with C<< >& >>, then the child will send output
+directly to that filehandle. In both cases, there will be a L<dup(2)>
+instead of a L<pipe(2)> made.
-If either reader or writer is the null string, this will be replaced
-by an autogenerated filehandle. If so, you must pass a valid lvalue
-in the parameter slot so it can be overwritten in the caller, or
-an exception will be raised.
+If either reader or writer is the empty string or undefined, this will
+be replaced by an autogenerated filehandle. If so, you must pass a
+valid lvalue in the parameter slot so it can be overwritten in the
+caller, or an exception will be raised.
The filehandles may also be integers, in which case they are understood
as file descriptors.
@@ -57,15 +67,15 @@ as file descriptors.
open3() returns the process ID of the child process. It doesn't return on
failure: it just raises an exception matching C</^open3:/>. However,
C<exec> failures in the child (such as no such file or permission denied),
-are just reported to CHLD_ERR under Windows and OS/2, as it is not possible
+are just reported to $chld_err under Windows and OS/2, as it is not possible
to trap them.
-If the child process dies for any reason, the next write to CHLD_IN is
+If the child process dies for any reason, the next write to $chld_in is
likely to generate a SIGPIPE in the parent, which is fatal by default.
So you may wish to handle this signal.
Note if you specify C<-> as the command, in an analogous fashion to
-C<open(FOO, "-|")> the child process will just be the forked Perl
+C<open(my $fh, "-|")> the child process will just be the forked Perl
process rather than an external command. This feature isn't yet
supported on Win32 platforms.
@@ -78,14 +88,14 @@ processes. See L<perlfunc/waitpid> for more information.
If you try to read from the child's stdout writer and their stderr
writer, you'll have problems with blocking, which means you'll want
-to use select() or the IO::Select, which means you'd best use
+to use select() or L<IO::Select>, which means you'd best use
sysread() instead of readline() for normal stuff.
This is very dangerous, as you may block forever. It assumes it's
-going to talk to something like B<bc>, both writing to it and reading
+going to talk to something like L<bc(1)>, both writing to it and reading
from it. This is presumably safe because you "know" that commands
-like B<bc> will read a line at a time and output a line at a time.
-Programs like B<sort> that read their entire input stream first,
+like L<bc(1)> will read a line at a time and output a line at a time.
+Programs like L<sort(1)> that read their entire input stream first,
however, are quite apt to cause deadlock.
The big problem with this approach is that if you don't have control
|
From @GrinnzSorry... one more time. |
From @Grinnzipc_open23_docs.patchdiff --git a/ext/IPC-Open3/lib/IPC/Open2.pm b/ext/IPC-Open3/lib/IPC/Open2.pm
index 9e27144571..9c70e5b455 100644
--- a/ext/IPC-Open3/lib/IPC/Open2.pm
+++ b/ext/IPC-Open3/lib/IPC/Open2.pm
@@ -18,38 +18,41 @@ IPC::Open2 - open a process for both reading and writing using open2()
use IPC::Open2;
- $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'some cmd and args');
- # or without using the shell
- $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'some', 'cmd', 'and', 'args');
+ my $pid = open2(my $chld_out, my $chld_in, 'some', 'cmd', 'and', 'args');
+ # or passing the command through the shell
+ my $pid = open2(my $chld_out, my $chld_in, 'some cmd and args');
- # or with handle autovivification
- my($chld_out, $chld_in);
- $pid = open2($chld_out, $chld_in, 'some cmd and args');
- # or without using the shell
- $pid = open2($chld_out, $chld_in, 'some', 'cmd', 'and', 'args');
+ # read from parent STDIN and write to already open handle
+ open my $outfile, '>', 'outfile.txt' or die "open failed: $!";
+ my $pid = open2($outfile, '<&STDIN', 'some', 'cmd', 'and', 'args');
+ # read from already open handle and write to parent STDOUT
+ open my $infile, '<', 'infile.txt' or die "open failed: $!";
+ my $pid = open2('>&STDOUT', $infile, 'some', 'cmd', 'and', 'args');
+
+ # reap zombie and retrieve exit status
waitpid( $pid, 0 );
my $child_exit_status = $? >> 8;
=head1 DESCRIPTION
-The open2() function runs the given $cmd and connects $chld_out for
+The open2() function runs the given command and connects $chld_out for
reading and $chld_in for writing. It's what you think should work
when you try
- $pid = open(HANDLE, "|cmd args|");
+ my $pid = open(my $fh, "|cmd args|");
-The write filehandle will have autoflush turned on.
+The $chld_in filehandle will have autoflush turned on.
If $chld_out is a string (that is, a bareword filehandle rather than a glob
or a reference) and it begins with C<< >& >>, then the child will send output
directly to that file handle. If $chld_in is a string that begins with
C<< <& >>, then $chld_in will be closed in the parent, and the child will
-read from it directly. In both cases, there will be a dup(2) instead of a
-pipe(2) made.
+read from it directly. In both cases, there will be a L<dup(2)> instead of a
+L<pipe(2)> made.
-If either reader or writer is the null string, this will be replaced
-by an autogenerated filehandle. If so, you must pass a valid lvalue
+If either reader or writer is the empty string or undefined, this will be
+replaced by an autogenerated filehandle. If so, you must pass a valid lvalue
in the parameter slot so it can be overwritten in the caller, or
an exception will be raised.
@@ -66,10 +69,10 @@ Failing to do this can result in an accumulation of defunct or "zombie"
processes. See L<perlfunc/waitpid> for more information.
This whole affair is quite dangerous, as you may block forever. It
-assumes it's going to talk to something like B<bc>, both writing
+assumes it's going to talk to something like L<bc(1)>, both writing
to it and reading from it. This is presumably safe because you
-"know" that commands like B<bc> will read a line at a time and
-output a line at a time. Programs like B<sort> that read their
+"know" that commands like L<bc(1)> will read a line at a time and
+output a line at a time. Programs like L<sort(1)> that read their
entire input stream first, however, are quite apt to cause deadlock.
The big problem with this approach is that if you don't have control
@@ -77,8 +80,8 @@ over source code being run in the child process, you can't control
what it does with pipe buffering. Thus you can't just open a pipe to
C<cat -v> and continually read and write a line from it.
-The IO::Pty and Expect modules from CPAN can help with this, as they
-provide a real tty (well, a pseudo-tty, actually), which gets you
+The L<IO::Pty> and L<Expect> modules from CPAN can help with this, as
+they provide a real tty (well, a pseudo-tty, actually), which gets you
back to line buffering in the invoked command again.
=head1 WARNING
diff --git a/ext/IPC-Open3/lib/IPC/Open3.pm b/ext/IPC-Open3/lib/IPC/Open3.pm
index e5924a30a6..4260604226 100644
--- a/ext/IPC-Open3/lib/IPC/Open3.pm
+++ b/ext/IPC-Open3/lib/IPC/Open3.pm
@@ -19,37 +19,47 @@ IPC::Open3 - open a process for reading, writing, and error handling using open3
=head1 SYNOPSIS
- $pid = open3(\*CHLD_IN, \*CHLD_OUT, \*CHLD_ERR,
- 'some cmd and args', 'optarg', ...);
-
- my($wtr, $rdr, $err);
- use Symbol 'gensym'; $err = gensym;
- $pid = open3($wtr, $rdr, $err,
- 'some cmd and args', 'optarg', ...);
-
+ use Symbol 'gensym'; # vivify a separate handle for STDERR
+ my $pid = open3(my $chld_in, my $chld_out, my $chld_err = gensym,
+ 'some', 'cmd', 'and', 'args');
+ # or pass the command through the shell
+ my $pid = open3(my $chld_in, my $chld_out, my $chld_err = gensym,
+ 'some cmd and args');
+
+ # 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');
+
+ # write to parent STDOUT and STDERR
+ my $pid = open3(my $chld_in, '>&STDOUT', '>&STDERR',
+ 'some', 'cmd', 'and', 'args');
+
+ # reap zombie and retrieve exit status
waitpid( $pid, 0 );
my $child_exit_status = $? >> 8;
=head1 DESCRIPTION
-Extremely similar to open2(), open3() spawns the given $cmd and
-connects CHLD_OUT for reading from the child, CHLD_IN for writing to
-the child, and CHLD_ERR for errors. If CHLD_ERR is false, or the
-same file descriptor as CHLD_OUT, then STDOUT and STDERR of the child
-are on the same filehandle (this means that an autovivified lexical
-cannot be used for the STDERR filehandle, see SYNOPSIS). The CHLD_IN
+Extremely similar to open2(), open3() spawns the given command and
+connects $chld_out for reading from the child, $chld_in for writing to
+the child, and $chld_err for errors. If $chld_err is false, or the
+same file descriptor as $chld_out, then STDOUT and STDERR of the child
+are on the same filehandle. This means that an autovivified lexical
+cannot be used for the STDERR filehandle, but gensym from L<Symbol> can
+be used to vivify a new glob reference, see L</SYNOPSIS>. The $chld_in
will have autoflush turned on.
-If CHLD_IN begins with C<< <& >>, then CHLD_IN will be closed in the
-parent, and the child will read from it directly. If CHLD_OUT or
-CHLD_ERR begins with C<< >& >>, then the child will send output
-directly to that filehandle. In both cases, there will be a dup(2)
-instead of a pipe(2) made.
+If $chld_in begins with C<< <& >>, then $chld_in will be closed in the
+parent, and the child will read from it directly. If $chld_out or
+$chld_err begins with C<< >& >>, then the child will send output
+directly to that filehandle. In both cases, there will be a L<dup(2)>
+instead of a L<pipe(2)> made.
-If either reader or writer is the null string, this will be replaced
-by an autogenerated filehandle. If so, you must pass a valid lvalue
-in the parameter slot so it can be overwritten in the caller, or
-an exception will be raised.
+If either reader or writer is the empty string or undefined, this will
+be replaced by an autogenerated filehandle. If so, you must pass a
+valid lvalue in the parameter slot so it can be overwritten in the
+caller, or an exception will be raised.
The filehandles may also be integers, in which case they are understood
as file descriptors.
@@ -57,15 +67,15 @@ as file descriptors.
open3() returns the process ID of the child process. It doesn't return on
failure: it just raises an exception matching C</^open3:/>. However,
C<exec> failures in the child (such as no such file or permission denied),
-are just reported to CHLD_ERR under Windows and OS/2, as it is not possible
+are just reported to $chld_err under Windows and OS/2, as it is not possible
to trap them.
-If the child process dies for any reason, the next write to CHLD_IN is
+If the child process dies for any reason, the next write to $chld_in is
likely to generate a SIGPIPE in the parent, which is fatal by default.
So you may wish to handle this signal.
Note if you specify C<-> as the command, in an analogous fashion to
-C<open(FOO, "-|")> the child process will just be the forked Perl
+C<open(my $fh, "-|")> the child process will just be the forked Perl
process rather than an external command. This feature isn't yet
supported on Win32 platforms.
@@ -78,14 +88,14 @@ processes. See L<perlfunc/waitpid> for more information.
If you try to read from the child's stdout writer and their stderr
writer, you'll have problems with blocking, which means you'll want
-to use select() or the IO::Select, which means you'd best use
+to use select() or L<IO::Select>, which means you'd best use
sysread() instead of readline() for normal stuff.
This is very dangerous, as you may block forever. It assumes it's
-going to talk to something like B<bc>, both writing to it and reading
+going to talk to something like L<bc(1)>, both writing to it and reading
from it. This is presumably safe because you "know" that commands
-like B<bc> will read a line at a time and output a line at a time.
-Programs like B<sort> that read their entire input stream first,
+like L<bc(1)> will read a line at a time and output a line at a time.
+Programs like L<sort(1)> that read their entire input stream first,
however, are quite apt to cause deadlock.
The big problem with this approach is that if you don't have control
|
From @jkeenanOn Mon, 10 Sep 2018 22:18:06 GMT, grinnz@gmail.com wrote:
There is a lot to this patch. In what follows I'm responding only to the sections dealing with IPC::Open2.
In the section above you have reversed the order in which the variants are
In the section above you have removed the "using shell" example. Was that
I think your substitution of 'command' for '$cmd' is good, because what the
I think it would be better if you left "write filehandle" in, then went on to Also, shouldn't '$chld_in' be 'C<$chld_in>'?
-- |
The RT System itself - Status changed from 'new' to 'open' |
From @GrinnzThanks for reviewing, and let me know if there are any parts that should be On Tue, Oct 9, 2018 at 10:29 AM James E Keenan via RT <
Yes, as for most users the shell is the less safe but sometimes necessary
I didn't think the variation needed to be represented again and distract
I substituted out '$cmd' because it was no longer being used in the
I feel it's confusing once you start calling them 'write' or 'read' Variables weren't in C<> so I kept that consistent but I can update them -Dan |
Migrated from rt.perl.org#133509 (status was 'open')
Searchable as RT133509$
The text was updated successfully, but these errors were encountered: