Системная команда 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
открыть дескриптор файла и выполнить ввод-вывод в вашей программе.