Saltar al contenido

Analizar argumentos de línea de comandos en un script de Ruby

Este grupo de expertos pasados ciertos días de trabajo y de recopilar de información, obtuvimos la solución, queremos que te sea útil en tu trabajo.

Solución:

El OptionParser incorporado de Ruby hace esto muy bien. Combínalo con OpenStruct y estarás en casa gratis:

require 'optparse'

options = 
OptionParser.new do |opt|
  opt.on('--first_name FIRSTNAME') o
  opt.on('--last_name LASTNAME')  options[:last_name] = o 
end.parse!

puts options

options contendrá los parámetros y valores como un hash.

Guardar y ejecutar eso en la línea de comando sin parámetros da como resultado:

$ ruby test.rb

Ejecutándolo con parámetros:

$ ruby test.rb --first_name=foo --last_name=bar
:first_name=>"foo", :last_name=>"bar"

Ese ejemplo está usando un Hash para contener las opciones, pero puede usar un OpenStruct que dará como resultado un uso como su solicitud:

require 'optparse'
require 'ostruct'

options = OpenStruct.new
OptionParser.new do |opt|
  opt.on('-f', '--first_name FIRSTNAME', 'The first name')  
  opt.on('-l', '--last_name LASTNAME', 'The last name') o
end.parse!

puts options.first_name + ' ' + options.last_name

$ ruby test.rb --first_name=foo --last_name=bar
foo bar

Incluso crea automáticamente su -h o --help opción:

$ ruby test.rb -h
Usage: test [options]
        --first_name FIRSTNAME
        --last_name LASTNAME

También puedes usar banderas cortas:

require 'optparse'

options = 
OptionParser.new do |opt|
  opt.on('-f', '--first_name FIRSTNAME')  options[:first_name] = o 
  opt.on('-l', '--last_name LASTNAME')  
end.parse!

puts options

Corriendo eso a través de sus pasos:

$ ruby test.rb -h
Usage: test [options]
    -f, --first_name FIRSTNAME
    -l, --last_name LASTNAME
$ ruby test.rb -f foo --l bar
:first_name=>"foo", :last_name=>"bar"

También es fácil agregar explicaciones en línea para las opciones:

OptionParser.new do |opt|
  opt.on('-f', '--first_name FIRSTNAME', 'The first name')  
  opt.on('-l', '--last_name LASTNAME', 'The last name')  options[:last_name] = o 
end.parse!

y:

$ ruby test.rb -h
Usage: test [options]
    -f, --first_name FIRSTNAME       The first name
    -l, --last_name LASTNAME         The last name

OptionParser también admite la conversión del parámetro a un tipo, como un número entero o una matriz. Consulte la documentación para obtener más ejemplos e información.

También debe mirar la lista de preguntas relacionadas a la derecha:

  • “Análisis de opciones de línea de comandos realmente barato en Ruby”
  • “Pasar variables al script de Ruby a través de la línea de comandos”

Basado en la respuesta de @MartinCortez, aquí hay una breve excepción que hace un hash de keypares /valor, donde los valores se deben unir con un = firmar. También admite argumentos de bandera sin valores:

args = Hash[ ARGV.join(' ').scan(/--?([^=s]+)(?:=(S+))?/) ]

…o alternativamente…

args = Hash[ ARGV.flat_maps ]

llamado con -x=foo -h --jim=jam vuelve "x"=>"foo", "h"=>nil, "jim"=>"jam" para que puedas hacer cosas como:

puts args['jim'] if args.key?('h')
#=> jam

Si bien hay varias bibliotecas para manejar esto, incluidas GetoptLong incluido con Ruby: personalmente prefiero rodar el mío. Este es el patrón que uso, lo que lo hace razonablemente genérico, no está vinculado a un formato de uso específico y es lo suficientemente flexible como para permitir banderas, opciones y argumentos necesarios entremezclados en varios órdenes:

USAGE = <'default', :writer=>'chm'  # Setting default values
UNFLAGGED_ARGS = [ :directory ]              # Bare arguments (no flag)
next_arg = UNFLAGGED_ARGS.first
ARGV.each do |arg|
  case arg
    when '-h','--help'      then ARGS[:help]      = true
    when 'create'           then ARGS[:create]    = true
    when '-f','--force'     then ARGS[:force]     = true
    when '-n','--nopreview' then ARGS[:nopreview] = true
    when '-v','--version'   then ARGS[:version]   = true
    when '-s','--shell'     then next_arg = :shell
    when '-w','--writer'    then next_arg = :writer
    when '-o','--output'    then next_arg = :output
    when '-l','--logfile'   then next_arg = :logfile
    else
      if next_arg
        ARGS[next_arg] = arg
        UNFLAGGED_ARGS.delete( next_arg )
      end
      next_arg = UNFLAGGED_ARGS.first
  end
end

puts "DocuBot v#DocuBot::VERSION" if ARGS[:version]

if ARGS[:help] or !ARGS[:directory]
  puts USAGE unless ARGS[:version]
  puts HELP if ARGS[:help]
  exit
end

if ARGS[:logfile]
  $stdout.reopen( ARGS[:logfile], "w" )
  $stdout.sync = true
  $stderr.reopen( $stdout )
end

# etc.

Yo personalmente uso Docopt. Esto es mucho más claro, fácil de mantener y fácil de leer.

Eche un vistazo a la documentación de la implementación de Ruby para ver ejemplos. El uso es realmente sencillo.

gem install docopt

código rubí:

doc = < --last_name=
DOCOPT

begin
  args = Docopt::docopt(doc)
rescue Docopt::Exit => e
  puts e.message
  exit
end

print "Hello #args['--first_name'] #args['--last_name']"

Entonces llamando:

$ ./says_hello.rb --first_name=Homer --last_name=Simpsons
Hello Homer Simpsons

Y sin argumentos:

$ ./says_hello.rb
Usage:
  says_hello.rb --first_name= --last_name=

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *