Is it possible to use array version of Perls syste

2019-09-07 07:07发布

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.

标签: linux perl
2条回答
smile是对你的礼貌
2楼-- · 2019-09-07 08:06

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' );
查看更多
劫难
3楼-- · 2019-09-07 08:11

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',
   );
}
查看更多
登录 后发表回答