From ff1e34624862f933ee737240f5b9aa0ad5c5b9f2 Mon Sep 17 00:00:00 2001 From: Andy Lester Date: Sun, 17 Mar 2024 12:58:17 -0500 Subject: [PATCH 1/2] First draft of quickstart --- lib/IPC/Run.pm | 125 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 123 insertions(+), 2 deletions(-) diff --git a/lib/IPC/Run.pm b/lib/IPC/Run.pm index 76a41a1..213610b 100644 --- a/lib/IPC/Run.pm +++ b/lib/IPC/Run.pm @@ -121,6 +121,129 @@ may be mixed. Various redirection operators reminiscent of those seen on common Unix and DOS command lines are provided. +=head1 SIMPLE QUICKSTART + +Here's a quick guide to basic usage of using IPC::Run's C function. + +=head2 Capturing output and errors from an external command + +Say you want to run a command in your shell. We'll use C for +simplicity, although there are far better ways to get a list of files, such +as the C function or the L module. + +The basic form of C has the command and its arguments passed as an +arrayref in the first argument. The command cannot be a single string. + + @cmd = [ 'ls', '-a', '-l', '-r', '-t' ]; # Yes + @cmd = ( 'ls -a -l -r -t' ); # No + +After the command, pass a scalar reference C<\$in> for the input to pass +in, and scalar references C<\$out> and C<\$err> to receive the content of +stdout and stderr. + + use IPC::Run qw( run ); + + @cmd = qw( ls -l -a -r -t ); + run( \@cmd, \$in, \$out, \$err ) or die $?; + + print("\$err is ", length($err), " bytes long\n"); + print($err, "\n"); + + print("\$out is ", length($out), " bytes long\n"); + print($out, "\n"); + +Running this will show something like: + + $err is 0 bytes long + + $out is 1410 bytes long + total 392 + drwxr-xr-x 3 andy staff 96 Mar 17 11:53 .github + -rw-r--r-- 1 andy staff 158 Mar 17 11:53 .gitignore + ... etc ... + +Note that C<$out> and C<$err> are always defined after a call to C, +even if they receive no data. + +=head2 Passing input to the external program + +If you have input to pass in, put it in the C<$in> variables. For example, +to use the C command to count lines, words and characters in a block of +text: + + $in = <<'CARROLL'; + 'Twas brillig, and the slithy toves + Did gyre and gimble in the wabe: + All mimsy were the borogoves, + And the mome raths outgrabe. + CARROLL + + @cmd = qw( wc ); + run( \@cmd, \$in, \$out, \$err ) or die $?; + print "$out"; + +This gives the output: + + 4 23 140 + +=head2 Handling errors + +It's important to check the return code of C to see if the command +ran successfully. C returns a boolean true on success, and false on +failure. Note that this is the opposite of Perl's C, which +returns 0 on success and a non-zero value on failures. + +For the specific subprocess error code, check C<$?> directly. + + @cmd = qw( tar xzvf nonexistent.tar ); + if ( !run( \@cmd, \$in, \$out, \$err ) ) { + print "\$? = $?\n"; + print "err = $err\n"; + } + +Running this gives: + + $? = 256 + err = tar: Error opening archive: Failed to open 'nonexistent.tar' + +If the program does not exist, then C will C and won't return +at all. For example: + + @cmd = qw( bogus-command ); + my $rc = run( \@cmd, \$in, \$out, \$err ); + print "run returned ", ($rc ? "true" : "false"), "\n"; + +Running this doesn't make it to the C statement. + + Command 'bogus-command' not found in [ list of paths ] at program.pl line N. + +To handle the possibility of a non-existent program, call C inside +an C. + + my $rc; + eval { $rc = run( \@cmd, \$in, \$out, \$out ); 1; }; + if ( !defined($rc) ) { + print "run died: $@\n"; + } + else { + if ( $rc ) { + print "run returned true\n"; + } + else { + print "run returned false\n"; + print "\$? = $?\n"; + } + } + +=head2 And beyond + +That's the basics of using C as a replacment for C. If +you'd like to do more, such as having subprocesses communicate with each +other, setting timeouts on long-running processes, kill running +subprocesses, redirecting output, closing file descriptors and much much MUCH more, read on. + +=head1 THE DETAILS + Before digging in to the details a few LIMITATIONS are important enough to be mentioned right up front: @@ -158,8 +281,6 @@ under the hood: =back -We now return you to your regularly scheduled documentation. - =head2 Harnesses Child processes and I/O handles are gathered in to a harness, then From a2467470bdcd1914bc4ca4ca462017889696832c Mon Sep 17 00:00:00 2001 From: Noah Misch Date: Sat, 30 Mar 2024 20:53:06 -0700 Subject: [PATCH 2/2] Fix pod typo; reflow paragraph; regenerate README.md --- README.md | 125 ++++++++++++++++++++++++++++++++++++++++++++++++- lib/IPC/Run.pm | 8 ++-- 2 files changed, 127 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 502e647..3dd56cf 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,129 @@ may be mixed. Various redirection operators reminiscent of those seen on common Unix and DOS command lines are provided. +# SIMPLE QUICKSTART + +Here's a quick guide to basic usage of using IPC::Run's `run()` function. + +## Capturing output and errors from an external command + +Say you want to run a command in your shell. We'll use `ls` for +simplicity, although there are far better ways to get a list of files, such +as the `glob()` function or the [File::Find](https://metacpan.org/pod/File%3A%3AFind) module. + +The basic form of `run()` has the command and its arguments passed as an +arrayref in the first argument. The command cannot be a single string. + + @cmd = [ 'ls', '-a', '-l', '-r', '-t' ]; # Yes + @cmd = ( 'ls -a -l -r -t' ); # No + +After the command, pass a scalar reference `\$in` for the input to pass +in, and scalar references `\$out` and `\$err` to receive the content of +stdout and stderr. + + use IPC::Run qw( run ); + + @cmd = qw( ls -l -a -r -t ); + run( \@cmd, \$in, \$out, \$err ) or die $?; + + print("\$err is ", length($err), " bytes long\n"); + print($err, "\n"); + + print("\$out is ", length($out), " bytes long\n"); + print($out, "\n"); + +Running this will show something like: + + $err is 0 bytes long + + $out is 1410 bytes long + total 392 + drwxr-xr-x 3 andy staff 96 Mar 17 11:53 .github + -rw-r--r-- 1 andy staff 158 Mar 17 11:53 .gitignore + ... etc ... + +Note that `$out` and `$err` are always defined after a call to `run()`, +even if they receive no data. + +## Passing input to the external program + +If you have input to pass in, put it in the `$in` variables. For example, +to use the `wc` command to count lines, words and characters in a block of +text: + + $in = <<'CARROLL'; + 'Twas brillig, and the slithy toves + Did gyre and gimble in the wabe: + All mimsy were the borogoves, + And the mome raths outgrabe. + CARROLL + + @cmd = qw( wc ); + run( \@cmd, \$in, \$out, \$err ) or die $?; + print "$out"; + +This gives the output: + + 4 23 140 + +## Handling errors + +It's important to check the return code of `run()` to see if the command +ran successfully. `run()` returns a boolean true on success, and false on +failure. Note that this is the opposite of Perl's `system()`, which +returns 0 on success and a non-zero value on failures. + +For the specific subprocess error code, check `$?` directly. + + @cmd = qw( tar xzvf nonexistent.tar ); + if ( !run( \@cmd, \$in, \$out, \$err ) ) { + print "\$? = $?\n"; + print "err = $err\n"; + } + +Running this gives: + + $? = 256 + err = tar: Error opening archive: Failed to open 'nonexistent.tar' + +If the program does not exist, then `run()` will `die` and won't return +at all. For example: + + @cmd = qw( bogus-command ); + my $rc = run( \@cmd, \$in, \$out, \$err ); + print "run returned ", ($rc ? "true" : "false"), "\n"; + +Running this doesn't make it to the `print` statement. + + Command 'bogus-command' not found in [ list of paths ] at program.pl line N. + +To handle the possibility of a non-existent program, call `run()` inside +an `eval`. + + my $rc; + eval { $rc = run( \@cmd, \$in, \$out, \$out ); 1; }; + if ( !defined($rc) ) { + print "run died: $@\n"; + } + else { + if ( $rc ) { + print "run returned true\n"; + } + else { + print "run returned false\n"; + print "\$? = $?\n"; + } + } + +## And beyond + +That's the basics of using `run()` as a replacement for `system()`. If you'd +like to do more, such as having subprocesses communicate with each other, +setting timeouts on long-running processes, kill running subprocesses, +redirecting output, closing file descriptors and much much MUCH more, read on. + +# THE DETAILS + Before digging in to the details a few LIMITATIONS are important enough to be mentioned right up front: @@ -152,8 +275,6 @@ to be mentioned right up front: $ IPCRUNDEBUG=gory myscript # (Win32 only) prints data moving through # the helper processes. -We now return you to your regularly scheduled documentation. - ## Harnesses Child processes and I/O handles are gathered in to a harness, then diff --git a/lib/IPC/Run.pm b/lib/IPC/Run.pm index 213610b..4e9abef 100644 --- a/lib/IPC/Run.pm +++ b/lib/IPC/Run.pm @@ -237,10 +237,10 @@ an C. =head2 And beyond -That's the basics of using C as a replacment for C. If -you'd like to do more, such as having subprocesses communicate with each -other, setting timeouts on long-running processes, kill running -subprocesses, redirecting output, closing file descriptors and much much MUCH more, read on. +That's the basics of using C as a replacement for C. If you'd +like to do more, such as having subprocesses communicate with each other, +setting timeouts on long-running processes, kill running subprocesses, +redirecting output, closing file descriptors and much much MUCH more, read on. =head1 THE DETAILS