Открыть дескриптор файла или назначить стандартный вывод

Я работаю в программе, в которой пользователь может передать параметр -o file, а затем вывод должен быть направлен в этот файл. В противном случае он должен перейти на стандартный вывод.

Чтобы получить опцию, я использую модуль getopt long, и это не проблема. Проблема в том, что я хочу создать дескриптор файла с этим файлом или назначить ему стандартный вывод, если параметр не был установлен.

if ($opt) {
    open OUTPUT, ">", $file;
} else {
    open OUTPUT, # ???
}

Это потому, что таким образом позже в моем коде я могу просто:

print OUTPUT "...";

Не беспокоясь о том, является ли OUTPUT стандартным выводом или файлом, указанным пользователем. Это возможно? Если я делаю плохой дизайн здесь, пожалуйста, дайте мне знать.


person cmre    schedule 14.08.2011    source источник
comment
Связано: stackoverflow.com/q/6296536#6296773   -  person daxim    schedule 24.08.2011


Ответы (3)


Это хороший пример использования select.

use strict;
use warnings;
use autodie;

my $fh;
if ($opt) {
    open $fh, '>', $file;
    select $fh;
}

print "This goes to the file if $opt is defined, otherwise to STDOUT."
person TLP    schedule 14.08.2011
comment
Хороший ТЛП, большое спасибо. Мне еще многое нужно узнать о Perl... Однако я не уверен, что это будет работать внутри while (<>), это не мой случай, просто думаю об этом. Повторное открытие stdout кажется лучшим вариантом в этих случаях, учитывая, что мне все равно придется маркировать печать. - person cmre; 14.08.2011
comment
@cmre О, вы отредактировали свой комментарий. Что ж, это будет работать так же хорошо, как повторное открытие STDOUT. print STDOUT "foo" по сути такой же, как print "foo", поэтому вам не нужно указывать дескриптор файла. Я не совсем уверен, что вас беспокоит, но вы должны использовать решение, которое вам удобно. - person TLP; 14.08.2011
comment
Да, только что отредактировал, извините. Проблема в том, что print "something" внутри while (<>) {...} выведет его в выбранный файл, верно? Или, может быть, нет, я только начинаю с Perl, и теперь это становится действительно запутанным: P - person cmre; 14.08.2011
comment
@cmre Я имею в виду, что с этим решением вам не нужно использовать print OUTPUT, вы можете просто использовать print. - person TLP; 14.08.2011
comment
Эх, да, print "something" будет печатать в STDOUT или текущий selected дескриптор файла, независимо от того, находитесь ли вы внутри цикла while или нет. Нахождение внутри цикла не имеет значения. - person TLP; 14.08.2011
comment
О, я понял. Еще раз извините, как я уже сказал, я просто запутался: я хотя print внутри <> печатал что-то в файл, указанный в качестве аргумента, но это то, что происходит при использовании переменной $^I. Я начал использовать Perl для некоторых задач, которые я выполнял с помощью sed в течение многих лет, поэтому я часто использую -i. - person cmre; 14.08.2011
comment
@cmre ‹› для ВВОДА. select() и print() предназначены для ВЫВОДА. Они не связаны. - person tadmc; 15.08.2011

Посмотрите документацию open. Проще всего заново открыть сам STDOUT и не использовать дескриптор файла в своем коде.

if ($opt) {
    open(STDOUT, ">", $file);
}
...

print "this goes to $file or STDOUT\n";

(Конечно, добавьте проверку ошибок.)

person Mat    schedule 14.08.2011
comment
Что, если программа все равно выводит что-то на стандартный вывод, в то время как какой-то другой вывод (например, команды оболочки) отправляется в файл или, опционально, также на стандартный вывод? - person Ale; 09.07.2021

Постоянный элемент, такой как OUTPUT, не может быть назначен. Использование такой переменной, как $output, работает лучше. Например:

my ($output, $display_filename);
if ($opt)
{
    if ($opt eq '-')
    {
        $display_filename = 'stdout';
        $output = *STDOUT;
    }
    else
    {
        $display_filename = $opt;
        open($output, '>', $opt) or
            die("Cannot open $opt for writing: $!\n");
    }
}

Таким образом, программа может печатать на стандартный вывод и/или в выходной файл:

print $output "This might go to a file\n";
print "Data written to $display_filename\n" if ($verbose);
person Ale    schedule 09.07.2021