Системная команда Perl с выводом нескольких параметров в файл

Мне нужно вызвать системную команду, используя форму:

system( $cmd, @args );

Когда я определяю @args как

my @args = ( "input1", "input2", ">", "file.out" );

">" И "file.out" не интерпретируются, как я надеялся. Как я могу отправить вывод этой формы системной команды в файл?

2 ответа

Решение

Это передает четыре аргумента программе, как если бы вы выполнили следующее в оболочке:

 prog "input1" "input2" ">" "file.out"

Вы не можете дать команду оболочке перенаправить вывод без использования оболочки!

Следующие решения предполагают:

my $prog = 'cat';
my @args = ( 'input1', 'input2' );
my $out_qfn = 'file.out';

В следующих решениях отсутствует проверка ошибок.

Решение 1

Используйте оболочку для выполнения перенаправления и экранирования.

system('/bin/sh', '-c', '"$@" > "$0"', $out_qfn, $prog, @args);

Решение 2

Используйте оболочку для выполнения перенаправления и используйте Perl для выполнения экранирования.

use String::ShellQuote qw( shell_quote );

my $cmd = shell_quote($prog, @args) . " >".shell_quote($out_qfn);
system('/bin/sh', '-c', $cmd);

Последняя строка упрощается до

system($cmd);

Решение 3

Избегайте использования оболочки. Используйте Perl для выполнения перенаправления.

# This isn't safe if @args is empty.

open(my $out_fh, '>', $out_qfn)
   or die("Can't create output file \"$out_qfn\": $!\n");

open(my $pipe, '-|', $prog, @args)
   or die $!;

while (<$pipe>) {
   print($out_fh $_);
}

close($fh);

или же

# This isn't safe if @args is empty.

use IPC::Open3 qw( open3 );

{
   open(local *CHILD_STDIN, '<', '/dev/null')
      or die $!;

   open(local *CHILD_STDOUT, '>', $out_qfn)
      or die("Can't create output file \"$out_qfn\": $!\n");

   my $pid = open3('<&CHILD_STDIN', '>&CHILD_STDOUT', '>&STDERR', $prog, @args);
   waitpid($pid, 0);
}

или же

use IPC::Run3 qw( run3 );

run3([ $prog, @args ], \undef, $out_qfn);

или же

use IPC::Run qw( run );

run([ $prog, @args ], \undef, $out_qfn);

Это потому что > file.out это особенность оболочки Используя system таким образом, как вы - вы обходите оболочку и передаете аргументы непосредственно в вызываемую программу.

Обратите внимание, что обработка аргументов варьируется в зависимости от количества аргументов. Если в LIST имеется более одного аргумента или если LIST является массивом с более чем одним значением, запускается программа, заданная первым элементом списка, с аргументами, заданными остальной частью списка. Если есть только один скалярный аргумент, этот аргумент проверяется на наличие метасимволов оболочки, и, если они есть, весь аргумент передается в системную командную оболочку для анализа (это /bin/sh -c на платформах Unix, но зависит от другие платформы). Если в аргументе нет метасимволов оболочки, он разбивается на слова и передается непосредственно в execvp, что более эффективно. В Windows только системный синтаксис PROGRAM LIST будет надежно избегать использования оболочки; system LIST, даже с более чем одним элементом, будет возвращаться к оболочке, если первый спавн не удался.

И, таким образом, перенаправление не работает - возможно, ваша программа игнорирует или иным образом обрабатывает передаваемые аргументы > а также file.out,

Вы можете сделать одну строку "система":

system ( "$cmd @args" );

Или использовать open открыть дескриптор файла и выполнить ввод-вывод в вашей программе.

Другие вопросы по тегам