Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Non-shell-invoking system/exec and qx//

by Anonymous Monk
on Jun 18, 2008 at 14:04 UTC ( [id://692707]=perlquestion: print w/replies, xml ) Need Help??

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

Dear monks,

exec(), system(), and "open" accepts a list form to indicate that we do not want to spawn a shell. Is there something similar for backtick? readpipe() only accepts a scalar, apparently. Does this mean we have to use a pipe open manually?

Replies are listed 'Best First'.
Re: Non-shell-invoking system/exec and qx//
by pc88mxer (Vicar) on Jun 18, 2008 at 14:32 UTC
    Opening '-|' can take a list argument, so here's a substitute for backticks and readpipe given by ikegami in the thread CLASSPATH problem when using backticks:
    sub backticks { open(my $pipe, '-|', @_) or return; local $/ = wantarray ? $/ : undef; <$pipe> }
    Note that a shell could still get invoked if @_ == 1 and the first element contains shell metacharacters.

      Note that a shell could still get invoked if @_ == 1 and the first element contains shell metacharacters.

      Good point. And rather unfortunate. Many commands accept '--' as an argument to signify the end of the command line switches. You could pass that if you're executing such a program.

      backticks('ls foo'); # Run "ls" with argument "foo" backticks('ls foo', '--'); # Run "ls foo" with argument "--"
      IPC::System::Simple is an alternate solution that doesn't suffer from that bug.

      Update: Oops, didn't notice it was already mentioned below.

Re: Non-shell-invoking system/exec and qx//
by Fletch (Bishop) on Jun 18, 2008 at 14:15 UTC

    Yup. qx// is syntactic sugar for the common case; if you want custom you've got to roll your own (or maybe use IPC::Run).

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: Non-shell-invoking system/exec and qx//
by ikegami (Patriarch) on Jun 18, 2008 at 14:33 UTC
    sub backticks { open(my $pipe, '-|', @_) or return; local $/ = wantarray ? $/ : undef; <$pipe> }

    Update: LOL! pc88mxer beat me to posting my own code!

Re: Non-shell-invoking system/exec and qx//
by brian_d_foy (Abbot) on Jun 18, 2008 at 15:26 UTC

    Update: Duh. I should post when I'm too sleepy to think straight.

    The system and exec send something to the command shell no matter how you call it (that's the point of those built-ins :). The list form just means that the elements after the command name won't be interpreted as shell meta-characters. You're still using the shell though.

    --
    brian d foy <brian@stonehenge.com>
    Subscribe to The Perl Review

      Erm, if you pass a list they call execvp(3) directly rather than starting up a shell. If there's one argument but it doesn't have anything more exotic than whitespace it's split and passed to execvp rather than run through a shell. See the exec and system entries in perlfunc; or look under the hood at pp_system in pp_sys.c and Perl_do_exec3 in doio.c.

      Update: this is only on fork-available /bin/sh-having OSen I believe; I can't speak to what unnatural machinations are done elsewhere as my eyes started to glaze over with some of the #ifdef'ing going on.

      The cake is a lie.
      The cake is a lie.
      The cake is a lie.

      ... You're still using the shell though.

      Don't think so (at least not on Unix).  For example:

      $ strace -fq -eexecve perl -e 'system "/bin/echo", "foo"' execve("/usr/local/bin/perl", ["perl", "-e", "system \"/bin/echo\", \" +foo\""], [/* 71 vars */]) = 0 [pid 27279] execve("/bin/echo", ["/bin/echo", "foo"], [/* 71 vars */]) + = 0

      So, no shell involved...

      That's not true. No shell is involved in the second snippet. (Check the ppid of ps.)

      $ perl -e'system "ps -opid,ppid,cmd 2>/dev/null"' PID PPID CMD 11096 7077 -bash 5166 11096 perl -esystem "ps -opid,ppid,cmd 2>/dev/null" 13220 5166 sh -c ps -opid,ppid,cmd 2>/dev/null 19387 13220 ps -opid,ppid,cmd $ perl -e'system "ps -opid,ppid,cmd"' PID PPID CMD 11096 7077 -bash 13513 11096 perl -esystem "ps -opid,ppid,cmd" 26826 13513 ps -opid,ppid,cmd
Use IPC::System::Simple for non-shell invoking system/exec/qx
by pjf (Curate) on Jun 23, 2008 at 02:42 UTC

    I believe that IPC::System::Simple is exactly what you're after. It provides a function called capture() that works just like backticks in how you'd call it, but never invokes the shell when called with multiple arguments.

    It has the advantages of running on both Unix and Windows, provides an easy way to get access to the exit value without manually unpacking $?, throws nice error strings on failure, is pure perl, and has no dependencies.

    Under Windows it has the added advantage of providing access to the full 32-bit return value, and avoids the bugs in Perl's core which can result in the shell being invoked anyway or potentially running the command twice.

    Note: I have some personal bias, as I'm the author of the module. ;)

    All the best,

      The author added capturex which is guaranteed not to call the shell, even if no arguments are provided.
Re: Non-shell-invoking system/exec and qx//
by repellent (Priest) on Jul 18, 2008 at 01:04 UTC
    I wrote exe() and bg() for that purpose because I felt that IPC::* syntaxes were non-intuitive, IMHO.

    Pipe processes and Perl subroutines together

    Internally, both functions perform safe forking methods to ensure no child zombies.

    Example to sort & number the list of /tmp files:
    use Exe; my @pids = &{ exe qw(ls /tmp), exe qw(sort -n), exe qw(cat -n), };

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://692707]
Approved by Corion
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (3)
As of 2024-03-29 05:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found