This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
IPC::Open2 and IPC::Open3 documentation updates
authorDan Book <grinnz@grinnz.com>
Wed, 18 Dec 2019 21:35:01 +0000 (16:35 -0500)
committerKarl Williamson <khw@cpan.org>
Fri, 13 Mar 2020 17:06:08 +0000 (11:06 -0600)
* Remove direct usage of bareword filehandles and use lexical filehandles for the first example in each synopsis.
* Add examples using STDIN and STDOUT filehandles, and examples using already open filehandles, with explicit examples of where these handles come from.
* Declare variables with 'my' where appropriate and condense declarations inline.
* Add comments in synopsis describing the purpose of each example.
* Consistency of referencing synopsis variables from the description.
* Replace ambiguous phrase 'null string' with 'empty string or undefined' which is also more correct here.
* Add links to referenced CPAN modules and manpages.
* Better describe the reason for using gensym in IPC::Open3 and how to use it.

ext/IPC-Open3/lib/IPC/Open2.pm
ext/IPC-Open3/lib/IPC/Open3.pm
t/porting/known_pod_issues.dat

index 9e27144..b4fef59 100644 (file)
@@ -18,38 +18,42 @@ 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 +70,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 +81,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 
index e5924a3..07f51c8 100644 (file)
@@ -19,37 +19,48 @@ 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 +68,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 +89,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
index 7b38d5f..c1c2720 100644 (file)
@@ -32,6 +32,7 @@ B::Lint
 B::Lint::Debug
 B::Utils
 basename(1)
+bc(1)
 Benchmark::Perl::Formance
 bind(2)
 BSD::Resource
@@ -108,6 +109,7 @@ Encode::Locale
 Eval::WithLexicals
 execvp(3)
 exit(3)
+Expect
 Exporter::Easy
 ExtUtils::Constant::ProxySubs
 fchdir(2)
@@ -156,6 +158,7 @@ indirect
 inetd(8)
 invoker
 IO::Compress
+IO::Pty
 IO::Socket::IP
 ioctl(2)
 IPC::Run
@@ -243,6 +246,7 @@ PerlIO::via::Base64
 PerlIO::via::StripHTML
 perllexwarn(1)
 perlthanks
+pipe(2)
 POD2::FR
 POD2::IT
 pod2ipf(1)
@@ -301,6 +305,7 @@ sock_init(3)
 Socket
 socketpair(3)
 SOM
+sort(1)
 splain
 sprintf(3)
 stat(2)