Как изменить стандартный дескриптор выходного файла для системного вызова в Perl? - PullRequest
1 голос
/ 13 июня 2009

Я пытаюсь изменить стандартный вывод системной функции, используя select. Но, похоже, это не работает. Вывод системы выводится на консоль, а не перенаправляется в файл.

use strict;
use warnings;

chdir "C:\\Documents and Settings\\" or die "cannot open the dir\n";
open FH, ">out.txt" or die "cannot open out.txt\n";
select FH or die " cannot change the stdout\n";
system "dir /a" ; 

Хотя я могу сделать system "dir /a > out.txt", я хочу знать, почему вышеприведенный код не работает.

Ответы [ 5 ]

3 голосов
/ 14 июня 2009

Функция select изменяет дескриптор файла по умолчанию для вывода. Он не меняет STDOUT, который указывает на то, на что он указывает, независимо от того, является ли он дескриптором файла по умолчанию для вывода. Если вы хотите изменить STDOUT, вы должны сделать что-то вроде илебре или ответа Джона.

Когда вы запускаете дочерний процесс, он получает тот же стандартный вывод, что и родительский процесс. И все равно, какой дескриптор файла по умолчанию у родительского файла.

2 голосов
/ 13 июня 2009

Проблема с вашим кодом в том, что команда system не захватывает вывод для вас. Вы можете использовать qx//:

use strict;
use warnings;

open my $fh, ">", "output.txt" or die $!;
my $oldfh= select $fh;
print qx/ls -a/;
select $oldfh;
close $fh or warn $!;

Существуют и другие опции для запуска внешнего приложения и получения его результатов, например, модули IPC::Open2 и IPC::Open3. Они включены в perl по умолчанию.

Примечание: не используйте глобусы для файловых дескрипторов: они глобальные, а глобальные злые. Вместо этого используйте лексические переменные (FH против $fh). Кроме того, вы должны использовать три аргумента open вместо двух параметров, так как первый безопаснее, чем второй.

1 голос
/ 13 июня 2009

Может быть это помогает

1 голос
/ 13 июня 2009

Я не уверен, что «выбор» - это то, что вы ищете в этом случае. Чтобы перенаправить STDOUT в файл, вы можете сделать следующее:

use strict;
use warnings;
use IO::Handle;
open FH, "> out.txt";
STDOUT->fdopen( \*FH, 'w' ) or die $!;
print "Hello world!\n";
system "dir /a";

Надеюсь, это поможет!

0 голосов
/ 13 июня 2009

Я переназначаю файловые дескрипторы на системном (не Perl) уровне:

    sub reopen($$$) {
        open $_[0], $_[1]. '&='. fileno($_[2]) or die "failed to reopen: $!";
    }

    reopen *STDOUT,  '>', $new_stdout_handle;

Теперь все, что вы раскошелите, будет считать $ new_stdout_handle стандартным выводом.

Я вставил полный пример в суть: http://gist.github.com/129407

...