in reply to Re^2: quoting issue with system command (Win32)
in thread quoting issue with system command

It works for me.
my $hu_seq = 'value of $hu_seq'; my $hd_seq = 'value of $hd_seq'; my $contig = 'value of $contig'; my $alignment = 'value of $alignment'; my @command = ( 'echo', '-leprint for @ARGV', '--', '-p', 'blastn', '-d', "$hu_seq $hd_seq", '-i', $contig, '-o', $alignment ); 0 == system @command or die "system @command failed: $?";
>c:\progs\perl5100\bin\perl t.pl "-leprint for @ARGV" -- -p blastn -d "value of $hu_seq value of $hd_se +q" -i "value of $contig" -o "value of $alignment" >c:\progs\perl589\bin\perl t.pl "-leprint for @ARGV" -- -p blastn -d "value of $hu_seq value of $hd_se +q" -i "value of $contig" -o "value of $alignment" >c:\progs\perl580\bin\perl t.pl "-leprint for @ARGV" -- -p blastn -d "value of $hu_seq value of $hd_se +q" -i "value of $contig" -o "value of $alignment" >c:\progs\perl561\bin\perl t.pl "-leprint for @ARGV" -- -p blastn -d "value of $hu_seq value of $hd_se +q" -i "value of $contig" -o "value of $alignment"

Here's a version where what you said is true:

>c:\progs\perl560\bin\perl t.pl -leprint for @ARGV -- -p blastn -d value of $hu_seq value of $hd_seq - +i value of $contig -o value of $alignment

(Switch echo for $^X for another view.)

These are all ActivePerl builds.

Replies are listed 'Best First'.
Re^4: quoting issue with system command (Win32)
by tye (Sage) on May 13, 2009 at 00:56 UTC

    Thanks. It is nice that this got done. perl58delta says:

    The behavior of system() with multiple arguments has been rationalized. Each unquoted argument will be automatically quoted to protect whitespace, and any existing whitespace in the arguments will be preserved. This improves the portability of system(@args) by avoiding the need for Windows C<cmd> shell specific quoting in perl programs.

    Note that this change only applies to Win32.

    - tye        

      I guess what I learned about it is out of date, too.

      His example used "echo", which is something I expect of CMD.exe, not something that works with CreateProcess.

      I looked at the source, and can't make heads nor tails of it. I can't find the ActiveState source on their site anymore, so I looked at the generic perl source.

      So, does it always run the shell? I thought the list form would bypass it. I think it's high time that we update the docs with what really happens.

      —John

        system(@list) bypasses the shell under Unix (and similar OSes) because system uses the Unix-like shell in order to parse command-line arguments. Under Win32, using the shell (cmd.exe) is done for other reasons. In both environements, I/O redirection is something that the shell is used for.

        In Win32, cmd.exe is also used for getting at quite a few "internal" commands including "echo", "dir", "copy", and "move". So even if you don't have any "shell meta characters", cmd.exe will get invoked if trying to run the command without it fails (basically).

        ActiveState doesn't maintain Perl source code. The code in question is very likely in http://cpansearch.perl.org/src/NWCLARK/perl-5.8.9/win32/win32.c, for example.

        - tye        

Re^4: quoting issue with system command (Win32)
by almut (Canon) on May 13, 2009 at 01:41 UTC

    Interestingly, when I run your snippet with an ActivePerl 5.8.8, I get the undesirable behavior (no quoting) you report with 5.6.0:

    c:\>perl t.pl -leprint for @ARGV -- -p blastn -d value of $hu_seq value of $hd_seq - +i value of $contig -o value of $alignment

    So there seems to be more to it than just version > 5.6.0 (?)

    In order to keep, lets say, 'value of $alignment' together as one argument, I have to define an ugly my $alignment = '\"value of $alignment\"';.

    c:\>perl -v This is perl, v5.8.8 built for MSWin32-x86-multi-thread (with 25 registered patches, see perl -V for more detail) Copyright 1987-2006, Larry Wall Binary build 817 [257965] provided by ActiveState http://www.ActiveSta +te.com Built Mar 20 2006 17:54:25
      That makes no sense. I have that exact build, and I get quotes:
      >c:\progs\perl588_817\bin\perl t.pl "-leprint for @ARGV" -- -p blastn -d "value of $hu_seq value of $hd_se +q" -i "value of $contig" -o "value of $alignment" >c:\progs\perl588_817\bin\perl -v This is perl, v5.8.8 built for MSWin32-x86-multi-thread (with 25 registered patches, see perl -V for more detail) Copyright 1987-2006, Larry Wall Binary build 817 [257965] provided by ActiveState http://www.ActiveSta +te.com Built Mar 20 2006 17:54:25 Perl may be copied only under the terms of either the Artistic License + or the GNU General Public License, which may be found in the Perl 5 source ki +t. Complete documentation for Perl, including FAQ lists, should be found +on this system using "man perl" or "perldoc perl". If you have access to + the Internet, point your browser at http://www.perl.org/, the Perl Home Pa +ge.

      Maybe your echo is different. (Got cygwin?) Try switching echo for $^X:

      >c:\progs\perl588_817\bin\perl t.pl -p blastn -d value of $hu_seq value of $hd_seq -i value of $contig -o value of $alignment
        Maybe your echo is different.

        Ah, right, that seems to be the issue — apparently, my echo is swallowing the quotes...  With $^X, perl is being passed the arguments as expected:

        c:\>perl t.pl -p blastn -d value of $hu_seq value of $hd_seq -i value of $contig -o value of $alignment

        So far so good.  OTOH, the reason I had tried this again at all was that I dimly remembered having had "issues" with the multi-argument form of system() recently (on Windows):  I had to pass a double-quoted value (a filename with spaces) through to another script (outside of my control), which itself was then calling system(). Due to the way the script was written, one level of quoting was being removed, which is why the argument itself needed to contain double quotes around the filename.

        I had tried something like this

        my $outfile = '\"c:\Documents and Settings\foo\my file\"'; my @command = ( $^X, '-leprint for @ARGV', '--', '-o', $outfile ); 0 == system @command or die "system @command failed: $?";

        expecting that $outfile would automatically get an outer pair of double quotes added around the specified value. However, it didn't, producing

        c:\>perl t.pl -o "c:\Documents and Settings\foo\my file"

        while the corresponding one-argument form works fine

        my $outfile = '\"c:\Documents and Settings\foo\my file\"'; my $command = qq($^X -le"print for \@ARGV" -- -o "$outfile"); 0 == system $command or die "system $command failed: $?"; __END__ -o "c:\Documents and Settings\foo\my file"

        Seems kind of inconsequent to me that with the multi-argument form, you still have to fiddle with the quoting yourself, i.e. add extra outer double quotes like this

        my $outfile = '"\"c:\Documents and Settings\foo\my file\""';

        to get the correct behavior. Why isn't this being done by Perl, when other values are apparently being quoted properly?

      Perhaps you have an echo.exe in your %PATH% such that Perl's system("echo ...") runs echo.exe instead of asking cmd.exe to use its internal echo command. For example, if you have cygwin installed, you'd get cygwin's echo.exe which will interpret the quotes and not output them instead of cmd.exe's echo command which includes the quotes in the output:

      C:\>\Apps\cygwin\bin\echo.exe "foo" foo C:\>echo "foo" "foo"

      Unfortunately, this is a new laptop and I only have cygwin Perl installed at the moment so I can't demonstrate the situation more directly (since cygwin Perl uses /bin/sh for system not cmd.exe).

      Change the test script to use 'cmd', '/c', 'echo' instead of just 'echo' ? Or change %PATH% or rename echo.exe temporarily.

      - tye        

        Change the test script to use 'cmd', '/c', 'echo'

        For the record, yes, this produces the expected (quoted) output.