0

Is it possible to use the array version of perls system command (i.e. the version that takes the first element as the command and the rest of the array as the cmd arguments) while also spawning a new process with Linux so that the system command returns immediately e.g. to run a command like:

mycmd arg1 arg2 &

I've tried using system( ('mycmd', 'arg1', 'arg2', '&') ) but it just interprets the ampersand literally as a third argument.

I know I can just pass the whole command as a scalar to system but I'm specifically wondering if it's possible to use the array version because the parameters for this command will originate from user options in a CGI script.

RTF
  • 6,214
  • 12
  • 64
  • 132
  • 2
    [`system`](http://perldoc.perl.org/functions/system.html) forks a new process and execs your shell command there. Any arguments you pass in the shell command get executed in this other process so while you may pass an `&` to make it work in the background; It is really the background of this other process that was started not your current one. – Hunter McMillen Jan 23 '15 at 13:54

2 Answers2

6

The & part of the shell command tells the shell to run the process in the background, so bypassing the shell by using the multi-arg form of system makes no sense.

Solution 1: Quote using String::ShellQuote.

use String:ShellQuote qw( shell_quote );
system(shell_quote('mycmd', 'arg1', 'arg2').' &');

Solution 2: Quote using shell interpolation.

system('sh', '-c', '"$@" &', 'sh', 'mycmd', 'arg1', 'arg2');

Solution 3: Launch the program in the background yourself.

use IPC::Open3 qw( open3 );

{
   open(local *CHILD_IN, '<', '/dev/null') or die $!;
   local $SIG{CHLD} = 'IGNORE';
   open3(
      '<&CHILD_IN', '>&STDOUT', '>&STDERR',
      'mycmd', 'arg1', 'arg2',
   );
}
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • None of these solutions will work for me. I can run the command and it does return immediately, but the script still waits at the end for the underlying command to complete. I posted a separate question which hopefully is more appropriate: http://stackoverflow.com/questions/28126351/end-perl-script-without-waiting-for-system-call-to-return?noredirect=1#comment44625794_28126351 – RTF Jan 24 '15 at 14:42
  • I realized that my problem is not specifically or solely a Perl problem, because the solutions here work if I run my perl script directly from a terminal. Although my web server and CGI script setup causes "something" to wait until the underlay system command has completed before returning a response to the web request, which is what the other Q is about. – RTF Jan 24 '15 at 16:17
1

Since you have no interest in the fate of the executed program you can use fork/exec. And you're on Linux which allows using $SIG{CHLD} = 'IGNORE' to avoid waiting on the child process.

sub background { 
    local $SIG{CHLD} = 'IGNORE';
    # fork and then exec if we are the child
    exec(@_) or die($!) unless fork; 
}
background( 'mycmd', 'arg1', 'arg2' );
Ben Grimm
  • 4,316
  • 2
  • 15
  • 24
  • This solution will not work for me. I can run the command and it does return immediately, but the script still waits at the end for the underlying command to complete. I posted a separate question which hopefully is more appropriate: http://stackoverflow.com/questions/28126351/end-perl-script-without-waiting-for-system-call-to-return?noredirect=1#comment44625794_28126351 – RTF Jan 24 '15 at 14:43