2009-08-13 13 views
4

Je ne cherche pas forcément un meilleur moyen de le faire, plutôt des explications sur la sortie seraient grandement appréciées. Récemment, un programmeur senior m'a demandé pourquoi son code fonctionnait mais seulement pour une instance. Ce que je suis venu à découvrir, c'est que cela a fonctionné tous les autres événements. Voici mon exemple:Pourquoi le glob de Perl revient-il undef pour tous les autres appels?

#!/usr/bin/perl -w 
use strict; 

my @list_env_vars = (
    '$SERVER', 
    '$SERVER', 
    '$SERVER', 
    '$SERVER', 
    '$SERVER', 
    '$SERVER', 
); 

foreach (@list_env_vars){ 
    print "$_ = ".glob()."\n"; 
} 

dont la sortie pour perl 5.004:

$SERVER = UNIX_SERVER 
$SERVER = 
$SERVER = UNIX_SERVER 
$SERVER = 
$SERVER = UNIX_SERVER 
$SERVER = 

ou de sortie pour perl 5.10:

$SITE = $SITE 
Use of uninitialized value in concatenation (.) or string at glob_test.pl line 14. 
$SITE = 
$SITE = $SITE 
Use of uninitialized value in concatenation (.) or string at glob_test.pl line 14. 
$SITE = 
$SITE = $SITE 
Use of uninitialized value in concatenation (.) or string at glob_test.pl line 14. 
$SITE = 

J'ai personnellement jamais utilisé glob() de cette façon si J'étais mal équipé pour lui répondre. J'ai lu la documentation perldoc glob et j'ai suivi le lien File::Glob sur cette page et je n'ai toujours pas trouvé de quoi expliquer la sortie. Toute aide serait très appréciée.

+0

Utilisera probablement perl 5.004 en raison des restrictions sur les machines auxquelles il sera distribué. – Akers

Répondre

13

glob dans un contexte scalaire:

Dans un contexte scalaire, itère glob par ces extensions de noms de fichiers, de retour FNUD lorsque la liste est épuisée.

Dans

foreach (@list_env_vars){ 
    print "$_ = ".glob()."\n"; 
} 

Le glob() il est vraiment glob($_). Chaque itération, $_ contient la chaîne $SERVER. Étant donné que la variable d'environnement ne change pas, $SERVER est étendu à la même chaîne. Première fois, cette chaîne est renvoyée. Ensuite, la liste est épuisée, donc undef est renvoyé. La troisième fois, nous recommençons. ...

Précision: Peu importe que l'argument au second appel est le même que celui pour le premier appel car il n'y a aucun moyen de réinitialiser glob de iterator.

Vous pouvez le voir plus clairement en utilisant l'exemple suivant (répertoire courant contient de 1.A 'fichiers, 1.b », '2.a' et '2.b'):

#!/usr/bin/perl -w 
use strict; 

my @patterns = (
    '*.a', 
    '*.b', 
); 

for my $v (@patterns) { 
    print "$v = ", scalar glob($v), "\n"; 
} 

sortie:

 
C:\Temp> d 
*.a = 1.a 
*.b = 2.a 

Je recommande l'accès aux variables d'environnement via le hachage %ENV:

my @list_env_vars = ($ENV{SERVER}) x 6; 

ou

my @list_env_vars = @ENV{qw(HOME TEMP SERVER)}; 
+0

Je n'arrive toujours pas à comprendre pourquoi cela fonctionne tous les autres cas, mais merci pour votre réponse. – Akers

+1

@Akers vous donnez à 'glob' une expression qui se développe en une seule chaîne unique. D'abord, il vous renvoie cela, ensuite il retourne 'undef'. Tout comme la documentation l'indique. –

+0

'Cette personne ne sait-elle pas qu'il peut accéder à la valeur de la variable d'environnement via $ ENV {SERVER}? Que diriez-vous de ' ouais en fait, j'ai suggéré d'utiliser $ ENV {}, j'étais juste curieux de savoir comment cela a fonctionné, je n'ai jamais utilisé glob de cette façon avant. Je viens d'utiliser plusieurs versions de la même env var pour prouver mon point. Peu importe si vous utilisez 6 variables différentes, vous obtenez toujours la même sortie. Chaque autre variable imprime. – Akers

4

Soit dit en passant, la raison pour laquelle à 5,004 vous obtenez une expansion variable tandis que sur 5.10 vous obtenez juste votre chaîne littérale en arrière, parce que sur le vieux perl, glob() a été réalisée par le shell système, qui vient comme l'effet secondaire effectue une expansion variable. Depuis Perl 5.6, glob() utilise le module File::Glob qui fait le travail lui-même, sans le shell, et ne développe pas les variables d'environnement (ce que glob n'a jamais été destiné à faire). %ENV est le bon moyen d'obtenir à l'environnement.

+0

merci, c'était quelque chose que je soupçonnais à propos de l'ancien version de glob, mais ne savait pas où chercher pour la vérification. – Akers

0

Notes sur l'ancien comportement, wiki'd pour votre commodité (et que je la gamme complète de balisage et aucune limite de 500 char):

Le fait que changé glob et <*globbything*> à 5,6 est mentionné en passant dans les docs (perl56delta, perlop, -f glob) mais la seule vraie source sur exactement comment il travaillait est une version antérieure à 5.6 de perlop. Voici le bit correspondant de 5,005:

Exemple:

while (<*.c>) { 
    chmod 0644, $_; 
} 

est équivalent à

open(FOO, "echo *.c | tr -s ' \t\r\f' '\\012\\012\\012\\012'|"); 
while (<FOO>) { 
    chop; 
    chmod 0644, $_; 
} 

En fait, il est actuellement mis en œuvre de cette façon. (Ce qui signifie qu'il ne fonctionnera pas sur les noms de fichiers contenant des espaces, sauf si vous avez csh (1) sur votre machine.)

Heh, c'est vraiment mal. Quoi qu'il en soit, si vous avez envie de consulter de vieux perldocs comme ça, allez sur search.cpan.org, retrouvez la distribution perl, utilisez la liste déroulante pour sélectionner une ancienne version, puis cliquez sur le document dont vous avez besoin. perl lui-même n'est pas vraiment sujet à être "rangé" du CPAN; Actuellement, tout à partir de 5.004 est disponible sans appuyer sur BackPan.