2010-03-15 21 views
24

Ruby J'ai besoin pour analyser une ligne de commande commeComment analyser un argument sans nom avec optparse

script.rb <mandatory filename> [options] 

avec optparse. Bien sûr, je peux écrire du code personnalisé pour gérer le nom de fichier, puis passer le ARGV à optparse, mais peut-être y a-t-il une façon plus simple de le faire?

EDIT: il existe une autre méthode hacky pour analyser une telle ligne de commande, et c'est passer ['--mandatory-filename'] + ARGV à optparse, puis gérer l'option --mandatory-filename.

+0

Voir ci-dessous les réponses, sans aucun doute; cependant, je vous recommande d'échanger vos paramètres 'filename obligatoire 'et' options'.En règle générale, les arguments non-switch venir en dernier sur une ligne de commande, sauf si vous avez une raison particulière de faire autrement –

Répondre

38

Première parse! avec optparse, puis balayez l'ARGV et augmenter si ARGV est vide. Comme si:

op.parse! 
filename = ARGV.pop 
raise "Need to specify a file to process" unless filename 

Le nom du fichier obligatoire ne sera pas traitée par le OptionParser et sera laissé pour vous argv - si ce n'est pas là, il suffit d'augmenter manuellement.

+1

utiliser quelque chose comme 'op.banner + = « »' pour régler la 'Utilisation:' la ligne en conséquence . – sschuberth

+1

ne serait pas 'ARGV.shift' au lieu de' ARGV.pop' serait mieux si nous voulions étendre à plusieurs paramètres requis? – nhed

+0

DNHE, ouais bonne idée depuis la première un ou deux arguments de position sont ceux habituellement nécessaires et ces derniers sont facultatifs (comme la façon avec 'zip' vous devez d'abord mettre le nom de fichier pour l'archive, puis une liste de fichiers qui se zippé dans le archiver). –

0

optparse ne fait que des arguments avec des paramètres, AFAIK. La façon "correcte" de gérer votre nom de fichier est de le traiter en dehors d'optparse. J'ai posté quelques exemples de code pour cela en réponse à this question.

BTW, c'est un plutôt inhabituel commandline. Si c'est juste pour vous, très bien, mais d'autres sont susceptibles de trouver cela plutôt contre-intuitif. Il serait plus normal d'avoir: script.rb [options] <filename> ...

+0

Merci, point pris –

+0

OptParse gère toutes sortes d'options. Il fait des drapeaux, des paramètres, des paramètres facultatifs, des listes, des booléens. Voir [Exemple complet] (http://ruby-doc.org/ruby-1.9/classes/OptionParser.html) pour plus d'informations. –

9

Juste pour revenir sur ce que Julik et Shadowfirebird dit: Lors de l'analyse avec OptionParser sachez que parse! et parse ont des fonctionnalités différentes. Le premier supprimera tous les arguments qu'il comprend du tableau passé où ce dernier les laissera être. Cela modifie vos conditions pour déterminer si l'argument requis est présent.

3

Bien qu'elle ne concerne pas toutes les situations, il est souvent agréable d'être en mesure de traiter plusieurs fichiers sur une seule ligne de commande, par exemple:

script.rb [options] file1 file2 ... 

fichier1 est obligatoire, mais fichier2 et au-delà est optionnel.

La meilleure façon que je sais faire cela suit cette convention:

options = {} 
optparse = OptionParser.new do |opts| 
    opts.banner = "Usage: script.rb [options] file1 file2 ..." 

    opts.on('-a', '--an-option ARG', 'Set some option') do |arg| 
    options[:a] = arg 
    end 

    ... 
end 
optparse.parse! 

# Check required conditions 
if ARGV.empty? 
    puts optparse 
    exit(-1) 
end 

Si les fichiers ne sont pas fournis, un message d'aide sera affiché avec la bannière d'utilisation et une description des options. Si les fichiers sont présents, ils seront la seule chose qui reste dans ARGV.

1

Je ne sais pas si elle a été ajoutée récemment, mais aucune des réponses précédentes ne mentionne que optparse.parse renverra la valeur ARGV après avoir supprimé les options analysées.

Si vous faites ceci:

rest = optparse.parse! 

Vous obtiendrez un tableau avec les fichiers données/s (avec des options inconnues). De cette façon, vous n'avez pas à vous soucier si les options viennent avant ou après le fichier.