2017-08-20 10 views
2

test.pl:Perl 5: Impossible d'obtenir le descripteur de descripteur de fichier

#!/usr/bin/perl 

use warnings; 

BEGIN { 
    *CORE::GLOBAL::close = sub (;*) { 
     my @Args = @_; 
     my $FileNO = fileno($Args[0]); 
     print $FileNO, "\n"; 
     CORE::close(@Args); 
    }; 
} 

use lib '.'; 
use Test; 

Test.pm:

package Test; 

open(XXX, 'test.pl'); 
close(XXX); 

1; 

Quand je lance ce programme (perl test.pl), je reçois:

Use of uninitialized value $FileNO in print at test.pl line 10. 

close() on unopened filehandle 1 at test.pl line 11. 

Où est l'erreur?

+4

utilisation Manquant 'strict' (et' utilisation warnings' dans Test.pm). N'appelez pas votre propre module 'Test.pm'; il y a déjà un module 'Test' standard. 'close (@Args)' est incorrect car 'close' impose un contexte scalaire sur ses arguments. – melpomene

+3

Voir aussi ['perldoc perlsub'] (http://perldoc.perl.org/perlsub.html#Prototypes) et rechercher' qualified_to_ref'. – melpomene

+0

@melpomene Si 'close (@Args)' est incorrect, alors qu'est-ce qui est juste? – porton

Répondre

0

Vous transmettez l'intégralité du tableau @Args en CORE::close, qui n'est pas un descripteur de fichier. Vous devez passer dans l'élément correct du tableau. Voici un exemple qui prend un nom de fichier à partir de la ligne de commande, et fait la bonne chose:

use warnings; 
use strict; 

BEGIN { 
    *CORE::GLOBAL::close = sub (;*) { 
     my @Args = @_; 
     my $FileNO = fileno($Args[0]); 
     print $FileNO, "\n"; 

     # the next line is where the issue is 

     CORE::close($Args[0]); 
    }; 
} 

die "need file param" if ! @ARGV; 

my $file = $ARGV[0]; 

open my $fh, $file or die $!; 

close $fh or die $!; 

Je vais aller plus loin avec ce que vous avez. Tout d'abord, je vais redéfinir les choses pour que le remplacement de la fonction CORE se fasse dans le fichier .pm au lieu du fichier de test, ensuite je vais passer à l'utilisation des descripteurs de fichiers lexicaux, car les noms globaux de bareword ne fonctionneront pas ici:

Test.pm:

package Test; 

BEGIN { 
    *CORE::GLOBAL::close = sub (;*) { 
     my @Args = @_; 
     my $FileNO = fileno($Args[0]); 
     print $FileNO, "\n"; 
     CORE::close($Args[0]); 
    }; 
} 

1; 

fichier script:

use warnings; 
use strict; 

use lib '.'; 
use Test; 

open my $fh, 'test.pl' or die $!; 
close $fh or die $!; 

Entre le code migration et à l'aide des descripteurs de fichiers lexicales, les choses devraient fonctionner comme on peut s'y attendre.

sortie de l'exécution du script:

3 

... et assurer que tout est en ordre, je vais revenir à la configuration par défaut, où le remplacement est dans le script de test, pas le module :

Test.pm

package Test; 

open my $fh, 'test.pl' or die $!; 
close $fh or die $!; 

1; 

... et le script:

use warnings; 
use strict; 

BEGIN { 
    *CORE::GLOBAL::close = sub (;*) { 
     my @Args = @_; 
     my $FileNO = fileno($Args[0]); 
     print $FileNO, "\n"; 
     CORE::close($Args[0]); 
    }; 
} 

use lib '.'; 
use Test; 

sortie:

4 
+0

Vous n'avez pas répondu à la question du tout; vous avez simplement changé le code de test pour que ça n'arrive plus !!! Même avec votre changement, le code OP ne parvient pas à obtenir le fichier et ne parvient pas à fermer la poignée de fichier! – ikegami

+0

@ikegami La question OP était "où est l'erreur". J'ai fait de mon mieux sur cette base. J'ai corrigé l'erreur la plus flagrante. Où le correctif devait-il être implémenté? – stevieb

+0

Ajout d'un additif @ikegami. Est-ce mieux? – stevieb