Подтвердить что ты не робот

Захват вывода системы Perl()

Мне нужно запустить команду оболочки с помощью system() в Perl. Например,

system('ls')

Системный вызов будет печатать на STDOUT, но я хочу записать вывод в переменную, чтобы я мог делать будущую обработку с помощью своего кода Perl.

4b9b3361

Ответ 1

Для чего нужны обратные сигналы. Из perldoc perlfaq8:

Почему я не могу получить вывод команды с system()?

Вы путаете цель system() и обратных ссылок (` `). system()запускает команду и возвращает информацию о статусе выхода (в виде 16-битного значения: низкие 7 бит - это сигнал, с которого процесс умер, если он есть, и высокие 8 бит - это фактическое значение выхода). Backticks (``) запускают команду и вернуть то, что он отправил в STDOUT.

my $exit_status   = system("mail-users");
my $output_string = `ls`;

Подробнее см. perldoc perlop.

Ответ 2

IPC::Run - мой любимый модуль для такого рода задач. Очень мощный и гибкий, а также тривиально простой для небольших случаев.

use IPC::Run 'run';

run [ "command", "arguments", "here" ], ">", \my $stdout;

# Now $stdout contains output

Ответ 3

Просто используйте пример bash:

    $variable=`some_command some args`;

вот и все. вы не увидите на выходе каких-либо распечаток в STDOUT, потому что это перенаправлено на переменную. Этот пример неприменим для команды, которая взаимодействует с пользователем, за исключением того, что вы подготовили ответы. для этого вы можете использовать что-то вроде этого, используя стек команд оболочки:

    $variable=`cat answers.txt|some_command some args`;

внутри файла ответов .txt вы должны подготовить все ответы для some_command, чтобы правильно работать.

Я знаю, что это не лучший способ программирования:), но это самый простой способ достижения цели, специально для программистов bash.

Конечно, если вывод больше (ls с подкаталогом), вы не должны получать весь вывод сразу. Прочитайте команду так же, как вы читаете файл regullar:

open CMD,'-|','your_command some args' or die [email protected];
my $line;
while (defined($line=<CMD>)) {
    print $line; #or push @table,$line or do whatewer what you want processing line by line
}
close CMD;

Ответ 4

Я хотел запустить system() вместо backtacks, потому что мне хотелось увидеть результат rsync --progress. Тем не менее, я также хотел записать результат в случае, если что-то пойдет не так, в зависимости от возвращаемого значения. (Это для резервного копирования script). Это то, что я использую сейчас:

use File::Temp qw(tempfile);
use Term::ANSIColor qw(colored colorstrip);



sub mysystem {
    my $cmd = shift; #"rsync -avz --progress -h $fullfile $copyfile";
    my ($fh, $filename) = tempfile();
    # http://stackoverflow.com/a/6872163/2923406
    # I want to have rsync progress output on the terminal AND capture it in case of error.
    # Need to use pipefail because 'tee' would be the last cmd otherwise and hence $? would be wrong.
    my @cmd = ("bash", "-c", "set -o pipefail && $cmd 2>&1 | tee $filename");
    my $ret = system(@cmd);
    my $outerr = join('', <$fh>);
    if ($ret != 0) {
        logit(colored("ERROR: Could not execute command: $cmd", "red"));
        logit(colored("ERROR: stdout+stderr = $outerr", "red"));
        logit(colored("ERROR: \$? = $?, \$! = $!", "red"));
    }
    close $fh;
    system("rm $filename");
    return $ret;
}

# and logit() is sth like:
sub logit {
    my $s = shift;
    my ($logsec,$logmin,$loghour,$logmday,$logmon,$logyear,$logwday,$logyday,$logisdst)=localtime(time);
    $logyear += 1900;
    my $logtimestamp = sprintf("%4d-%02d-%02d %02d:%02d:%02d",$logyear,$logmon+1,$logmday,$loghour,$logmin,$logsec);
    my $msg = "$logtimestamp $s\n";
    print $msg;
    open LOG, ">>$LOGFILE";
    print LOG colorstrip($msg);
    close LOG;
}