Обратные апострофы и сохранение вывода

При использовании обеих функций system и exec выходные данные запущенной команды направляются в стандартный поток вывода Perl. Иногда бывает нужно сохранить этот вывод в строковом виде для дальнейшей обработки. Задача решается просто: замените апострофы или кавычки при создании переменной обратными апострофами ` `:

my $now = `date`; # Сохранить вывод date
print "The time is now $now"; # Символ новой строки уже присутствует

Обычно команда date выдает в стандартный вывод строку длиной приблизительно 30 символов. Строка содержит текущую дату и время и завершается символом новой строки. Когда мы заключаем вызов date в обратные апострофы, Perl выполняет команду date, сохраняет ее вывод в виде строкового значения и (в данном случае) присваивает ее переменной $now. Этот синтаксис очень близок к использованию обратных апострофов
в командном процессоре UNIX. Однако командный процессор также удаляет завершающий символ новой строки, чтобы упростить дальнейшее использование значения. Perl действует честнее: он выдает настоящие выходные данные. Чтобы получить тот же результат в Perl, нам пришлось бы обработать результат дополнительной операцией chomp:

chomp(my $no_newline_now = `date`);
print "A moment ago, it was $no_newline_now, I think.\n";

Значение в обратных апострофах интерпретируется как форма sуstem с одним аргументом по правилам строк в кавычках (то есть с интерпретацией служебных последовательностей с символом \ и расширением переменных).


Например, для получения документации по функциям Perl мы могли бы многократно вызвать perldoc с разными аргументами:

my @functions = qw{ int rand sleep length hex eof not exit sqrt umask };
my %about;
foreach (@functions) {
$about{$_} = `perldoc -t -f $_`;
}

Переменная $_ содержит разные значения при каждом вызове, что позволяет нам получать результаты разных вызовов, отличающихся только одним из параметров. Если эти функции вам еще незнакомы, загляните в документацию и посмотрите, что они делают. В синтаксисе обратных апострофов нет простого аналога режима «обычных» апострофов1: ссылки на переменные и комбинации с \ расширяются всегда. Также не существует простого аналога версии system с несколькими аргументами (выполняемой без участия командного процессора). Если команда в обратных апострофах достаточно сложна, для ее интерпретации автоматически активизируется UNIX Bourne Shell (или другой командный процессор, используемый в вашей системе). Постарайтесь обходиться без обратных апострофов в тех местах, где вывод не сохраняется. Пример:

print "Starting the frobnitzigator:\n";
`frobnitz -enable`; # Не делайте этого!
print "Done!\n";

Дело в том, что Perl приходится выполнять ряд дополнительных действий для сохранения вывода команды (который немедленно теряется), к тому же вы теряете возможность использования system с несколькими аргументами для более точного управления списком аргументов.


Итак, и с точки зрения эффективности, и с точки зрения безопасности system оказывается предпочтительнее. Стандартный поток ошибок наследуется командой в обратных апострофах от Perl. Если команда выводит сообщения об ошибках в стандартный поток ошибок, скорее всего, они будут выведены на терминал; это собьет с толку пользователя, который не запускал команду frobnitz. Если вы предпочитаете сохранять сообщения об ошибках в стандартном выводе, воспользуйтесь стандартным механизмом «слияния стандартного потока ошибок со стандартным потоком вывода» командного процессора; на языке UNIX это называется записью 2>&1:

my $output_with_errors = `frobnitz -enable 2>&1`;

Но в этом случае стандартный поток ошибок смешивается со стандартным выводом по аналогии с тем, как это происходит при выводе на терминал (хотя, возможно, в несколько иной последовательности из-за буферизации). Если вы предпочитаете разделить поток вывода и поток ошибок, существует пара более сложных решений. Стандартный поток ввода также наследуется от текущего стандартного ввода Perl. Как правило, команды, заключаемые в обратные апострофы, все равно не читают данные из стандартного ввода, так что это не создает особых проблем.


Но допустим, что команда date спрашивает, какой часовой пояс вам нужен (см. ранее). Строка с запросом направляется в стандартный вывод, сохраняется как часть результата, после чего команда date пытается получить данные из стандартного ввода. Но пользователь не видел запрос и не знает, что ему нужно вводить!

Вскоре он позвонит вам и скажет, что ваша программа «зависла». Итак, держитесь подальше от команд, читающих данные из стандартного ввода. Если вы не уверены в том, читаются данные из стандартного ввода или нет, добавьте перенаправление из /dev/null:

my $result = `some_questionable_command arg arg argh
В этом случае дочерний процесс командного процессора перенаправит ввод из /dev/null, а «внук» some_questionable_command в худшем случае попытается прочитать данные и немедленно получит признак конца файла.

Оцените статью: (0 голосов)
0 5 0

Статьи из раздела Perl на эту тему:
Ветвление
Выполнение команд в обход командного процессора
Обратные апострофы в списочном контексте
Отправка и прием сигналов
Переменные среды

Вернуться в раздел: Perl / 15. Управление процессами