2009-10-07 7 views
7

Comment imprimer sur une variable avec Perl?Comment puis-je imprimer sur une variable au lieu d'un fichier, en Perl?

Je travaille sur un programme pendant un certain temps qui enregistre son itérative progrès de façon très bavard ...

print $loghandle $some_message; 

Cependant, je voudrais également imprimer de manière sélective certains des messages à un fichier différent. Bien sûr, je pourrais saupoudrer avec le code ...

print $loghandle $some_message 
print $otherloghandle $some_message 

Ou réécrire toute l'entreprise en fonction. Blabla.

Ce que je veux faire est de faire de la magie quand j'ouvre le loghandle de $ pour que quand je suis print « ing, je suis en fait juste faire une opération sprintf ish contre une variable (appeler $current_iteration), de sorte que quand je suis à un point de décision que je peux faire quelque chose comme ça ...

print $real_log_file $current_iteration; 
print $other_real_log_file $current_iteration if($condition); 

Je suis assez sûr que je l'ai vu quelque chose comme ça quelque part, mais je ne sais pas où il est ou où chercher .

edit: File :: Tee résout ce problème dans une certaine mesure sur * nix, mais je cours sous Windows.

+2

Deja vu? http://stackoverflow.com/questions/1532544/how-can-i-send-stdout-and-stderr-to-a-log-file-and-to-the-screen-in-win32-perl/1532691# 1532691 –

+0

Peut-être. Je n'essaie pas de té les flux réels (même si cela n'a pas d'importance); il s'agit plutôt de définir une variable pour agir en tant que flux de destination. Je suis paresseux et je ne veux pas réécrire 50 messages de journalisation, voir. :-) –

+2

@Paul Nathan Je suis lié à la réponse de brian d foy. Utilisez Log4perl. Exprimez votre '$ condition' comme niveau de journalisation, définissez les actions. Je ne l'ajoute pas comme une réponse car je n'ai pas le temps de vérifier comment cela fonctionne, mais je recommande fortement Log4perl basé sur l'expérience passée. –

Répondre

18

Vous pouvez traiter une variable scalaire comme descripteur de fichier par open ing il:

open my $fh, '>', \$variable or die "Can't open variable: $!"; 
print $fh "Treat this filehandle like any other\n"; 

Vous pouvez même carte stdout ou stderr à un scalaire:

close STDOUT; 
open STDOUT, '>', \$variable or die "Can't open STDOUT: $!"; 

Si vous w Pour diviser votre sortie ou configurer un fichier de configuration pour faire des choses "intéressantes" avec votre journalisation, vous êtes mieux avec Log4Perl comme d'autres l'ont suggéré.

2

Vous pouvez utiliser File::Tee pour diviser un descripteur de fichier en plusieurs flux de sortie.

use File::Tee; 
open my $fh, '>', 'logfile.txt' or die $!; 
tee($fh, '>', 'otherlogfile.txt') if $condition; 

print $fh $current_iteration; # will also go to otherlogfile.txt 
           # if $condition was true 
+0

Je cours sur Windows (File :: Tee ne fonctionne pas). ajoutant cela à la question. –

1

Semblez que vous voulez tie votre handle de fichier.

my $x; 

# printing to $fh will update the variable $x 
# when you close $fh, it will print $x to a filehandle depending 
# on code in the function Print_to_variable::CLOSE 

tie $fh, "Print_to_variable", \$x, $output_fh1, $output_fh2; 
print $fh "stuff"; 
print $fh "more stuff"; 
close $fh; 

sub Print_to_variable::TIEHANDLE { 
    my ($class, $ref, $fh1, $fh2) = @_; 
    my $self = {}; 
    $self->{ref} = $ref; 
    $self->{output_fh1} = $fh1; 
    $self->{output_fh2} = $fh2; 
    bless $self, "Print_to_variable"; 
    $self; 
} 
sub Print_to_variable::PRINT { 
    my ($self,@list); 
    ${$self->{ref}} .= join "", @list; 
} 
sub Print_to_variable::CLOSE { 
    my $self = shift; 
    my $text = ${$self->{ref}}; 
    if (&myCondition1($text)) { # ... how you decide where to print 
     print {$self->{output_fh1}} $text; 
    } else { 
     print {$self->{output_fh1}} $text; 
    } 
} 
+0

Je pense, mais j'ai le bêtise aujourd'hui et je ne vois pas comment la cravate fonctionne vraiment ici. –

5

Voulez-vous dire quelque chose comme IO::Scalar? Vous permet d'écrire dans une variable avec la sémantique filehandle.

+3

Vous n'avez pas besoin d'IO :: Scalar explicitement. open() par lui-même fonctionne très bien. –

1

Ceci est un énorme hack, et je pense que la solution de Mobrule ou (en particulier) la solution de Log4Perl de Sinan sont la voie à suivre quand j'ai le temps.

Mais, ce que je suis en utilisant, comme une chose d'achèvement:

sub print_to_var($$) { 
    my($rx_var, $scalar) = @_; 
    $$rx_var .= $scalar; 
} 


print_to_var \$logvar, $message; 

#...later on... 
print $somefile $logvar; 

Edit:

Depuis c'est la communauté wiki, il ne vaut rien que Perl alias arguments aux fonctions. Cela signifie que vous pouvez simplement écrire ceci:

sub print_to_var($$) { 
    $_[0] .= $_[1]; 
} 

Et puis dire:

my $foo = "OH HAI. "; 
print_to_var $foo, "I ARE HELO KITTIE."; 
say $foo; # OH HAI. I ARE HELO KITTIE. 

Ce n'est pas un hack particulièrement énorme, même si print_to_var est beaucoup plus que taper . est.

Et voici le HELO KITTIE:

helo kittie http://blogs.philadelphiaweekly.com/style/files/2008/11/hello-kitty-color.gif

+0

Je suis amusé! Et je n'étais pas sûr de l'aliasing/referencing args aux fonctions. Je vous remercie! –

4

Si vous souhaitez effectuer une journalisation sélective vous permettant de contrôler quels messages sont consignés et où ils sont consignés, utilisez Log::Log4perl. Cela vous fera économiser beaucoup de temps à jouer avec tie s et d'autres magie noire.

Questions connexes