Как мне указать дескриптор файла на STDOUT (или другой дескриптор файла) в Perl? - PullRequest
25 голосов
/ 09 июня 2011

Я хочу сделать быстрый скрипт, который пишет в файл, если файл указан, или стандартный вывод, если файл не указан. Мне было бы намного легче сделать это, если бы я мог запустить скрипт, указав новый дескриптор файла, OUTFILE, в зависимости от того, что из этого подходит.

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

Все это говорит о том, что я ищу что-то вроде:
open( OUTFILE, ($output ? ">$output" : STDOUT );
за исключением того, что не работает.

Идеи

Ответы [ 5 ]

37 голосов
/ 09 июня 2011

Некоторые способы (globs):

# 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;
}

Некоторые способы (лексическая переменная):

# 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);
}
10 голосов
/ 09 июня 2011

Ради читателя (поскольку OP уже "заработал"):

В документации Perl "perlopentut" (perldoc perlopentut) приводятся примеры открытия альтернативного дескриптора файла, направленного на STDOUT, но в нем используется голое словофайловые дескрипторы и версия с двумя аргументами open, обе из которых несколько древние.В книге Дамиана Конвея "Perl Best Practices" (а также Perl :: Critic, основанной на книге Дамиана) подчеркивается использование трех открытий arg и лексических файловых дескрипторов (файловые дескрипторы стиля my $foo).В «Современном Perl» chromatic также кратко упоминается использование лексических файловых дескрипторов, и там, где это практически возможно, не рекомендуется использовать голые слова.Три arg open считается более безопасной формой, поскольку ограничивает воздействие инъекций оболочки.Несмотря на то, что в данном случае речь идет о малом риске, по-прежнему хорошей привычкой является использование по умолчанию трех аргументов open.

. Необходимо внимательно прочитать примеры, показанные в документации open Perl (perldoc -f open), и небольшая интерпретация, чтобы заметить правильное размещение символа амперсанда при открытии дубликата фила-ручки, направленной на 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 какссылка на typeglob:

open my $fh, '>&', \*STDOUT or ...
7 голосов
/ 09 июня 2011

- это магия. Следуйте соглашению или вы нарушаете принцип наименьшего удивления.

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 голосов
/ 09 июня 2011

Nevermind.Догадаться.Бросок в амперсанде делает свое дело.Полный рабочий код:
open( OUTPUT, ( $output ? ">$output" : ">&STDOUT" ) );

3 голосов
/ 09 июня 2011

Вы всегда можете просто записать обычный вывод в STDOUT и свои операторы отладки в STDERR. Затем, если пользователь хочет, чтобы вывод шел в файл, он может просто перенаправить STDOUT в файл в командной строке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...