2010-11-23 6 views
2

J'ai un script shell qui recrache une ligne comme suit:Comment utiliser Getopt :: Long pour analyser les arguments qui peuvent avoir des espaces?

prog_name -options ... 

Pour être plus précis, à titre d'exemple:

prog_name -filter_arg +define BOOST +noconvtest +actuate-long -disp_arg +define size=40 res=30

S'il vous plaît noter qu'il n'y a pas de citations ci-dessus et je ne pas de contrôle pour modifier le script shell. [Cependant, je ne suis pas sûr si je peux insérer des citations à la syntaxe ci-dessus par le biais d'un autre programme.].

Maintenant, je veux envoyer ci-dessus à un programme Perl pour analyser les options afin qu'il associe +define BOOST +noconvtest +actuate-long à l'option -filter_arg et +define size=40 res=30 l'option -disp_arg.

Quelqu'un peut-il m'aider s'il vous plaît à faire cela?

Répondre

0

Je ne suis pas sûr à 100%, mais je ne pense pas que vous puissiez utiliser GetOpt :: Long pour le faire, du moins pas directement.

Vous auriez besoin, je pense à faire une première vous passer, quelque chose comme

my @filters; 
my $filter = []; 

foreach (@ARGV) { 
    if ($_ eq '+filter') { 
    push @filters, $filter; 
    $filter = []; 
    } else { 
    push @$filter, $_; 
    } 
} 
push @filters, $filter if @$filter; 

foreach (@filters) { 
    Getopt::Long::GetOptionsFromArray(@$_, ... 

    ... 
} 
+0

Merci beaucoup Axeman, David et Colin. Vraiment apprécier votre réponse rapide. Et dans le véritable esprit de Perl, vous avez montré comment le problème peut être résolu de multiples façons! J'ai beaucoup appris après chacune de vos publications. Meilleurs voeux. – Silver2010

+0

Manque le point que les options ont été divisées par le shell, pas par Perl. – Demi

2

Vous pouvez passer un rappel comme ceci:

use strict; 
use warnings; 
use Getopt::Long; 

my $options = {}; 
@ARGV=qw<-filter_arg +define BOOST +noconvtest +actuate-long -disp_arg +define size=40 res=30>; 
GetOptions( 
    $options # store in hash ref 
    , qw<filter_arg define=s noconvtest actuate-long> 
    , disp_arg => sub { 
     # this will contain "+define size=40 res=30" 
     $options->{disp_arg} = join(' ', delete @ARGV[0..$#ARGV]); 
     } 
    ); 
5

Getopt::Long est simplement l'analyse syntaxique de la liste @ARGV comme prévu au programme Perl. Si les paramètres sont des entrées séparées dans la liste @ARGV, Getopt::Long les analysera de cette manière. Votre problème est que le shell place chaque argument comme un paramètre séparé puisqu'il n'y a pas de guillemets autour d'eux.

Votre choix est soit munge les paramètres avant votre script Perl exécute, ou par munging @ARGV lui-même de combiner les paramètres dans les valeurs qu'ils sont supposés être.

Pour la première option, vous pouvez utiliser sed pour prendre la sortie de votre programme et ajouter les citations manquantes. Si vous êtes programme crache toujours des champs comme ceci:

prog_name -filter_arg +define BOOST +noconvtest +actuate-long -disp_arg +define size=40 res=30 

Vous pourriez tuyau par sed comme ceci:

$ orig_prog | sed -e 's/filter_arg /filter_arg "/' -e 's/ -disp_arg /" -disp_arg "/' -e 's/$/"/' 

Ou ceci:

$ orig_prog | sed -e 's/^\(.*\) -filter_arg \(.*\) -disp_arg \(.*\)$/\1 -filter_arg "\2" -disp_arg "\3"/' 

Cela va mettre les citations autour de vos paramètres et il ressemblera à ceci:

prog_name -filter_arg "+define BOOST +noconvtest +actuate-long" -disp_arg "+define size=40 res=30" 

De cette façon, @ARGV sera configuré correctement pour que la fonction GetOptions fonctionne comme vous le souhaitez.

L'autre façon est de munge @ARGV une fois que vous êtes programme Perl fonctionne avant d'appeler GetOptions:

my $value; 
my @newArgv; 
foreach my $param (@ARGV) { 
    if ($param =~ /^-/) { 
    if ($value) { 
    push (@newArgv, $value); 
    $value = ""; 
    } 
    push(@newArgv, $param); 
    } else { 
    $value = $value ? "$value $param" : "$param"; 
    } 
} 
push (@newArgv, $value) if ($value); 
@ARGV = @newArgv; 

Dans l'exemple ci-dessus, @ARGV aura les valeurs suivantes:

@ARGV[0] = -filter_arg 
@ARGV[1] = +define BOOST +noconvtest +actuate-long 
@ARGV[2] = -disp_arg 
@ARGV[3] = +define size=40 res=30 

Et , Getopts::Long devrait maintenant fonctionner comme vous le souhaitez. Petite note: Dans les nouvelles versions de Getopt::Long, vous pouvez utiliser d'autres baies en plus de @ARGV. Vous mettez simplement le tableau que vous voulez utiliser comme premier argument dans GetOptions:

use Getopt::Long qw(GetOptionsFromArray); 

GetOptionsFromArray (
    \@newArgs, 
    "filter_arg=s" => \$filter_arg, 
    "disp_arg=s" => \$disp_arg, 
); 
0

de Getopt longue peut analyser votre ligne de commande est la suivante:

my (@filter_arg, @display_arg); 
GetOptions('filter_arg=f{1,5}' => \@filter_arg, 'display_arg=i{1,5}' => \@display_arg); 

Vous obtiendrez des tableaux de parms.

Veuillez voir Getopt::Long - Options with multiple values pour une explication plus détaillée de la gestion des paramètres à valeurs multiples déjà disponible.

Questions connexes