2009-06-13 6 views
1

J'essaye de changer le stdout de la fonction de système en utilisant select. Mais cela ne semble pas fonctionner. La sortie du système s'affiche sur la console plutôt que d'être redirigée vers le fichier.Comment puis-je modifier le handle de fichier de sortie standard pour un appel système en Perl?

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" ; 

Bien que je peux faire system "dir /a > out.txt", je veux savoir pourquoi le code ci-dessus ne fonctionne pas.

Répondre

3

La fonction select modifie le descripteur de fichier par défaut pour la sortie. Il ne modifie pas STDOUT, qui pointe vers tout ce qu'il pointe vers, qu'il s'agisse du gestionnaire de fichiers par défaut pour la sortie. Si vous voulez changer STDOUT, vous devez faire quelque chose comme ylebre ou la réponse de Jon.

Lorsque vous démarrez un processus enfant, il obtient la même sortie standard que le parent. Il ne se soucie pas de savoir quel est le handle de fichier par défaut du parent.

1

Je ne suis pas sûr que 'select' soit ce que vous cherchez dans ce cas. Pour rediriger stdout vers un fichier, vous pouvez effectuer les opérations suivantes:

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

Hope this helps!

+0

@ylebre, ne fonctionne pas. Changez la SORTIE en FH dans fdopen. Aussi, je voulais savoir pourquoi choisir ne fonctionnait pas. – chappar

2

Le problème avec votre code est que la commande system ne saisit pas la sortie pour vous. Vous pouvez utiliser 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 $!; 

Il y a d'autres options pour exécuter une application externe et d'obtenir lu sa sortie, comme les modules IPC::Open2 et IPC::Open3. Ils sont inclus dans Perl par défaut. A noter: n'utilisez pas de globs pour les poignées de fichiers: ce sont des globals, et les globals sont maléfiques. Utilisez plutôt les variables lexicales (FH vs. $fh). En outre, vous devez utiliser les trois arguments open au lieu de deux paramètres, car le premier est plus sûr que le second.

+0

Igor, mon argument est dir commande devrait obtenir la même stdout que celle du programme perl à partir de laquelle il a été appelé. Puisque nous avons en quelque sorte dupé stdout avec un fichier, la sortie du système ne devrait-elle pas aller dans le fichier? – chappar

+0

Non, ce n'est pas le cas. Lorsque vous exécutez system ("dir/a"), perl exécutera votre shell (dans votre cas, cmd.exe) comme un processus forké avec "dir/a" comme arguments. Lorsque vous utilisez qx //, perl renvoie la sortie de ce processus forké pour vous. J'espère que cela clarifie un peu. – Igor

-2

Je réaffectez les descripteurs de fichiers au niveau du système de niveau (non Perl):

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

    reopen *STDOUT, '>', $new_stdout_handle; 

Maintenant, tout ce que vous penserez fourchette new_stdout_handle $ est sortie standard.

J'ai collé un exemple complet essentiel: http://gist.github.com/129407

+0

Ce dé ne va pas être très utile si vous rouvrez STDERR. Il est préférable de sauvegarder le fichier stderr existant en ouvrant "> & STDERR" pour pouvoir le restaurer si la réouverture échoue. – ysth

Questions connexes