We tend to avoid the Windows shell in Perl scripts that run external commands in customer environments over which we have no control. Some years ago we got burnt because some of our customers use a misfeature of Windows cmd.exe, namely that without the /d option, cmd.exe executes stuff from one of the following Registry values:

HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\AutoRun HKEY_CURRENT_USER\Software\Microsoft\Command Processor\AutoRun
before running your command. In one case, I remember there was a "cd" command in the customer autorun Registry which caused one of our Perl scripts to malfunction. We worked around it by replacing `some command 2>&1` with `cmd /d/c "some command" 2>&1`. An alternative workaround is to manipulate STDOUT and STDERR from perl, while taking care to call the Perl system function in such a way that the shell is not invoked.

To clarify, the two approaches are illustrated by the following two example programs:

use strict; use warnings; my $cmd = 'perl -le "print qq{to stdout};print STDERR qq{to stde +rr};exit 42"'; my $cmdhack = qq{cmd /d/c $cmd 2>&1}; # works # my $cmdhack = qq{cmd /d/c "$cmd" 2>&1}; # also works (despite bizar +re quoting) print "run:$cmdhack:\n"; my $out = `$cmdhack`; my $rc = $? >> 8; print "rc=$rc, stdout/stderr of command follows:\n"; print $out;

and:

use strict; use warnings; my $outfile = 'ff.tmp'; my $exe = $^X; my @args = ( 'perl', '-le', 'print qq{to stdout};print STDERR qq{to + stderr};exit 42' ); print "run exe:$exe:args:@args:\n"; print STDERR "here we go to stderr\n"; open(SAVOUT, ">&STDOUT") or die "error: save original STDOUT: $!"; open(SAVERR, ">&STDERR") or die "error: save original STDERR: $!"; open(STDOUT, '>', $outfile) or die "error: create '$outfile': $!"; open(STDERR, '>&STDOUT') or die "error: redirect '$outfile': $!"; system { $exe } @args; my $rc = $? >> 8; open(STDOUT, ">&SAVOUT") or die "error: restore STDOUT: $!"; open(STDERR, ">&SAVERR") or die "error: restore STDERR: $!"; close(SAVERR) or die "error: close SAVERR: $!"; close(SAVOUT) or die "error: close SAVOUT: $!"; print "rc=$rc\n"; print STDERR "rc=$rc to STDERR\n";
Improvements welcome.

Update: tidied up and clarified the example code.


In reply to Re: capturing command output by eyepopslikeamosquito
in thread capturing command output by morgon

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.