Как я могу указать дескриптор файла в STDOUT (или другую файловую ручку) в Perl?
Я хочу сделать быстрый script, который записывает в файл, если файл указан, или stdout, если файл не указан. Мне было бы намного легче сделать это, если бы я мог запустить script, указав новый дескриптор файла OUTFILE на то, что из этого подходит.
Я знаю, что могу выполнить то, что хочу, просто указывая STDOUT на мой выходной файл, когда это уместно, но я бы предпочел не делать этого, поскольку я не хочу путать кого-либо, использующего script позже, и задаюсь вопросом, почему их печать заявления не работают. Кроме того, я по-прежнему хотел бы использовать случайный запрос печати самостоятельно для устранения неполадок и никогда не хочу, чтобы эта печать выводилась.
Все это говорит о том, что я ищу, что-то вроде:
open( OUTFILE, ($output ? ">$output" : STDOUT );
кроме того, что не работает.
Идеи?
Ответы
Ответ 1
Некоторые способы (глобусы):
# Requires 2-arg open, unfortunately
open(OUTPUT, "> ".($output || '-')) or die;
if ($output) {
open(OUTPUT, '>', $output) or die;
} else {
*OUTPUT = *STDOUT;
}
if ($output) {
open(OUTPUT, '>', $output) or die;
} else {
open(OUTPUT, '>&', \*STDOUT) or die;
}
Некоторые способы (лексический var):
# Requires 2-arg open, unfortunately
open(my $fh, "> ".($output || '-')) or die;
my $fh;
if ($output) {
open($fh, '>', $output) or die;
} else {
$fh = \*STDOUT;
}
my $fh;
if ($output) {
open($fh, '>', $output) or die;
} else {
open($fh, '>&', \*STDOUT) or die;
}
Некоторые способы (другие):
# Changes the default handle for <print "foo">.
if ($output) {
open(OUTPUT, '>', $output) or die;
select(OUTPUT);
}
Ответ 2
Для читателя (поскольку OP уже "получил работу" ):
В документации Perl "perlopentut" (perldoc perlopentut) приводятся примеры открытия альтернативного дескриптора файла, направленного на STDOUT, но он использует дескрипторы дескриптора файла и версию с двумя аргументами open
, обе из которых несколько древние. Книга Damian Conway "Perl Best Practices" (а также Perl:: Critic, которая основана на книге Дамиана) подчеркивает использование трех открытий arg и лексических дескрипторов файлов (my $foo
дескрипторов файла стиля). хроматический "Modern Perl" также вкратце упоминает использование лексических дескрипторов файлов и, в случае необходимости, отпугивает слова. Три arg open
считаются более безопасными, поскольку он ограничивает воздействие на инъекции оболочки. В то время как конкретный случай здесь имеет низкий риск, он по-прежнему является хорошей привычкой по умолчанию для трех-arg open
.
Необходимо внимательно прочитать примеры, показанные в документации Perl open
(perldoc -f open), и небольшую интерпретацию, чтобы заметить правильное размещение символа амперсанда при открытии дубликата filahandle, направленного на STDOUT
при использовании версия с тремя аргументами open
. Можно ошибочно предположить, что это должно работать: open my $fh, '>', '&STDOUT' or die $!;
, главным образом потому, что это выглядит как формат, который мы привыкли видеть (амперсанд и предшествующий имени символа). Но этот синтаксис не соответствует требованиям open
, и мы привыкли видеть его в совершенно другом контексте: некоторые вызовы подпрограмм.
Правильный способ открыть обход для STDOUT
с помощью трех arg open
состоит в объединении >
и &
в один и тот же второй аргумент и оставить STDOUT голыми, например:
use Modern::Perl;
open my $fh, '>&', STDOUT or die "Bleah: $!";
say $fh 'Printing alternate filehandle "$fh" worked.';
say 'Implicitly printing to "STDOUT" also works.';
Или передайте STDOUT
в open
в качестве ссылки на типglob:
open my $fh, '>&', \*STDOUT or ...
Ответ 3
-
- это магия. Следуйте за соглашением или нарушите принцип наименьшего удивления.
use autodie qw(:all);
use Getopt::Long qw(GetOptions);
GetOptions(\my %opt, 'out=s') or die 'usage';
die 'usage' unless $opt{out};
open my $handle, ">$opt{out}";
perl foo -o blahblah # opens file blahblah for writing
perl foo -o - # goes to STDOUT
Связано: Есть ли причины когда-либо использовать форму с двумя аргументами open (...) в Perl?
Ответ 4
Nevermind. Догадаться. Бросок в амперсанд делает трюк. Полный рабочий код:
open( OUTPUT, ( $output ? ">$output" : ">&STDOUT" ) );
Ответ 5
Вы всегда можете просто написать регулярный вывод в STDOUT
, а операторы отладки - STDERR
. Затем, если пользователь хочет, чтобы выход пошел в файл, он может просто перенаправить STDOUT в файл в командной строке.