2008-10-09 7 views
3

J'ai un sous-programme qui prend un handle de fichier comme argument. Comment puis-je créer un handle de fichier à partir d'un chemin de fichier spécifié sur la ligne de commande? Je ne veux pas faire moi-même le traitement de ce fichier, je veux juste le passer à cet autre sous-programme, qui renvoie un tableau de hachage avec toutes les données analysées du fichier.Comment puis-je obtenir un handle de fichier à partir de la ligne de commande?

Voici ce que l'entrée de ligne de commande J'utilise ressemble:

$ ./getfile.pl /path/to/some/file.csv

Voici ce que le début du sous-programme que j'appelle ressemble à:

sub parse { 
    my $handle = shift; 
    my @data = <$handle>; 
    while (my $line = shift(@data)) { 
     # do stuff 
    } 
} 
+0

Vous n'avez pas de handle de fichier, vous avez un fichier * nom *. A quoi le sous-programme s'attend-il? –

+0

J'ai mis à jour la question par question. – cowgod

Répondre

16

arguments de ligne de commande sont disponibles dans le tableau @ARGV prédéfini. Vous pouvez obtenir le nom de fichier à partir de là et utiliser open pour y ouvrir un descripteur de fichier. En supposant que vous voulez un accès en lecture seule au fichier, vous le feriez de cette façon:

my $file = shift @ARGV; 
open(my $fh, '<', $file) or die "Can't read file '$file' [$!]\n"; 
parse($fh); 

Notez que les or die... vérifie l'appel open pour le succès et meurt avec un message d'erreur si ce n'était pas. La variable intégrée $! contiendra le message d'erreur (dépendant de l'OS) en cas d'échec qui vous indique pourquoi l'appel n'a pas abouti. par exemple. "Permission refusée."

+0

Vous pouvez également utiliser 'autodie;' pour éviter de devoir vérifier manuellement l'appel 'open' pour le succès Actuellement, vous devez installer autodie depuis le CPAN, mais il sera probablement livré avec Perl à partir de 5.10.1 –

-1

Suis-je manque quelque chose ou cherchez-vous simplement l'appel open()?

open($fh, "<$ARGV[0]") or die "couldn't open $ARGV[0]: $!"; 
do_something_with_fh($fh); 
close($fh); 
+0

C'est faux. C'est ouvert mon $ fh, "<$ ARGV [0]". Le $ fh est le premier argument, pas la valeur de retour! (ou mieux encore ouvrir mon $ fh, '<', $ ARGV [0]. –

+0

corrigé, merci pour le heads-up – bmdhacks

5

parse(*ARGV) est la solution la plus simple: l'explication est un peu longue, mais une partie importante de l'apprentissage de l'utilisation efficace de Perl est d'apprendre Perl.

Lorsque vous utilisez un descripteur de fichier null (<>), il lit en fait de la ARGV magique filehandle, qui a une syntaxe particulière: il lit tous les fichiers nommés dans @ARGV ou STDIN si @ARGV est vide.

De perldoc perlop:

Le descripteur de fichier null <> est spécial: il peut être utilisé pour imiter le comportement de sed et awk. L'entrée de <> provient soit de l'entrée standard , soit de chaque fichier indiqué sur la ligne de commande. Voilà comment cela fonctionne : la première fois <> est évaluée, le tableau @ARGV est cochée, et si elle est vide, $ARGV[0] est réglé sur "-", qui, lorsqu'il est ouvert, vous donne entrée standard. Le tableau @ARGV est ensuite traité comme une liste de noms de fichiers . La boucle

while (<>) { 
    ...      # code for each line 
} 

est équivalent au code pseudo Perl comme suit:

unshift(@ARGV, '-') unless @ARGV; 
while ($ARGV = shift) { 
    open(ARGV, $ARGV); 
    while (<ARGV>) { 
     ...   # code for each line 
    } 
} 

sauf qu'il est pas si lourd à dire, et fait travailler. Il décale vraiment le tableau @ARGV et met le nom de fichier actuel dans la variable $ARGV.Il utilise également le handle de fichier ARGV en interne-- <> est juste un synonyme de <ARGV>, ce qui est magique. (Le pseudo-code ci-dessus ne travail parce qu'il traite <ARGV> comme non-magique.)

Vous ne devez pas utiliser <> dans une boucle while - my $data = <> va lire une ligne de la première non fichier vide, my @data = <>; slurp tout en même temps, et vous pouvez passer *ARGV comme s'il s'agissait d'un handle de fichier normal.

+0

Il ne répond pas tout à fait à la question ... mais en suggérant, à partir de là, que l'OP passe le handle de fichier ARGV à sa fonction le ferait (en supposant, bien sûr, que cela fonctionne - je ne l'ai pas essayé.) –

+0

Clarifié cette réponse pour dire que parse (* ARGV) fonctionne, au lieu de le mettre dans un commentaire sur la question. – ephemient

1

Voici à quoi sert le commutateur -n!

Prenez votre méthode d'analyse syntaxique, et faire ceci:

#!/usr/bin/perl -n 

#do stuff 

Chaque ligne est stocké dans $ _. Donc, vous exécutez

./getfile.pl /path/to.csv

Et il le fait.

Voir here et here pour plus d'informations à leur sujet. J'aime aussi -p, et j'ai trouvé que les combos de -a et -F étaient vraiment utiles.

De plus, si vous souhaitez effectuer un traitement supplémentaire, ajoutez BEGIN et les blocs de fin.

#!/usr/bin/perl -n 

BEGIN { 
    my $accumulator; 
} 

# do stuff 

END { 
    print process_total($accumulator); 
} 

ou autre. C'est très, très utile.

Questions connexes