Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I'm baffled, but maybe I need a second pair of glasses on top of the first one... What is the difference between:

my @qrsh_options = split / /, $qrsh_options; system 'qrsh', @qrsh_options, 'lens', '-n', "\"source $qscript; test_model $arguments\"", ">$output_file", "2>$logfile";
and system "qrsh $qrsh_options lens -n \"source $qscript; test_model $arguments\" >$output_file 2>$logfile";

The first works, the second causes an error (a Tcl error - the part between the \"...\" is Tcl, which is the internal script language used by lens, but which I don't know well, so I still write my wrappers in Perl). As far as I can see, the error must be due to a difference between the two variants of the system call, but I don't see where. I want to use capture_exec from IO::CaptureOutput instead of system, but I need the 2nd kind of syntax for that, and I can't get it right :-/

Replies are listed 'Best First'.
Re: Syntax details with "system"
by cheekuperl (Monk) on Jul 19, 2012 at 16:28 UTC
    As far as I can see, the error must be due to a difference between the two variants of the system call, but I don't see where.

    Check system. It says:
    If there is only one scalar argument, the argument is checked for shell metacharacters, and if there are any, the entire argument is passed to the system's command shell for parsing
    And
    If there is more than one argument in LIST, or if LIST is an array with more than one value, starts the program given by the first element of the list with arguments given by the rest of the list.

      I read that multiple times :-) (I wouldn't dare post otherwise). I guess my problem is that I don't understand what it says.

      What are "shell metacharacters"? All those variables are defined in the Perl script, so they should be resolved in the script. Are \" shell metacharacters? And what about > and <? They occur in Perl when you open a pipe, but this is sort of different...or maybe not...?

      Also, what difference does it make whether Perl starts qrsh with that whole list of arguments, or whether the shell does? And when Perl starts qrsh, what about > and <, *if* they are "shell metacharacters"? How do they get interpreted?

      In the one-argument case, I can print the whole string to see what it is resolved to. But what about the multiple argument case? How do I know what that really works out to (so that I can write the same thing in when I call capture_exec)?

        What are "shell metacharacters"?

        [ddg://What are "shell metacharacters"?] What are "shell metacharacters"? ... Characters used for input or output in UNIX shells having special meaning.

Re: Syntax details with "system"
by thewebsi (Scribe) on Jul 20, 2012 at 05:49 UTC

    Yes, the two forms are different.

    In the first form, a system call (eg, the C function as implemented internally by the operating system for executing commands) is made with the arguments provided. In the second form, the string is passed to the shell to deal with. The difficulty that you are running into is with escaping of meta-characters (characters special to the shell, but not special to the internal system call).

    The first form (system call) is equivalent to automatically escaping all arguments. So when you say above that the first form "works", it really doesn't, as it just passes ">$output_file" as an argument to the command, which in general won't do what you want. I don't know of any way to do something like piping to a file using the first form (you normally use open() for that instead).

    The second form (shell command) probably doesn't work for you because you are not escaping characters that you want escaped. Escaping can be done automatically in Perl using quotemeta() or \Q...\E.

    As an example, consider:

    >echo two > one

    If you want this to echo "two > one", then you need to escape the ">":

    system "echo", "two", ">", "one";
    system "echo two \\> one";
    system "echo " . quotemeta ( "two > one" );
    system "echo \Qtwo > one\E";

    If you want "two" to be piped to a file called "one", then you don't:

    system "echo two > one";


      Thanks Arnon. That answer was useful. I suspect the 1st form works because of the specifics here (qrsh is a Sun Grid Engine command which opens a shell on a node and runs "lens ... 2>$logfile"). I didn't realize it made a difference for the answer.

      I finally found out what characters exactly needed to be escaped how many times

      system "qrsh $qrsh_options \"lens -n \\\"source $qscript ; test_model +$arguments\\\" >$output_file 2>$logfile\"";
      I just read about quotemeta and I suspect it wouldn't work for me because all the $ would be escaped and the perl variables wouldn't be resolved. But I will remember \Q...\E for the future - I'm sure it will come in handy sometime :-)

Re: Syntax details with "system"
by Anonymous Monk on Jul 20, 2012 at 13:51 UTC

    I think the other posters roughly said it already, but I'll elaborate a bit from a systems programming standpoint.

    system($str) is equivalent, OS-wise, to forking, and then exec'ing sh -c "$str"

    system(@list) is equivalent to forking, setting ARGV to @list, and exec'ing the first item in @list.

    In the latter form, there is no shell involved, which means one fewer fork (more efficient), no need to think about escaping things for the shell (wonderful), and that it is a bit safer against untrusted input. On the downside, you cannot use shell features such as redirection or pipes.

    You are free to test what happens if you call this small perl script, let's call it showargs.pl with both styles:

    #!/usr/bin/perl use Data::Dumper; print Dumper(\@ARGV);

    Calling it with the following snippet, what do you expect the output to be? What about without the list-form invocation?

    system 'showargs.pl', 'lens', '-n', "\"source $qscript; test_model $arguments\"", ">$output_file", "2>$logfile";