Pase variables al script Ruby a través de la línea de comando


275

He instalado RubyInstaller en Windows y estoy ejecutando IMAP Sync pero necesito usarlo para sincronizar cientos de cuentas. Si pudiera pasarle estas variables a través de la línea de comando, podría automatizar mejor todo el proceso.

# Source server connection info.
SOURCE_NAME = 'username@example.com'
SOURCE_HOST = 'mail.example.com'
SOURCE_PORT = 143
SOURCE_SSL  = false
SOURCE_USER = 'username'
SOURCE_PASS = 'password'

# Destination server connection info.
DEST_NAME = 'username@gmail.com'
DEST_HOST = 'imap.gmail.com'
DEST_PORT = 993
DEST_SSL  = true
DEST_USER = 'username@gmail.com'
DEST_PASS = 'password'

1
Es posible que desee considerar editar esta pregunta popular en una pregunta real .
not2qubit

Respuestas:


465

Algo como esto:

ARGV.each do|a|
  puts "Argument: #{a}"
end

luego

$ ./test.rb "test1 test2"

o

v1 = ARGV[0]
v2 = ARGV[1]
puts v1       #prints test1
puts v2       #prints test2

84
Me gustaría señalar explícitamente que ARGV [0] no apunta al nombre del programa, como lo hacen algunos otros idiomas. Para obtener el nombre del programa, consulte stackoverflow.com/questions/4834821/…
Sander Mertens

3
¿No es "test1 test2" un solo argumento?
wuliwong

Es necesario añadir #!/usr/bin/env rubyen la parte superior del .rbarchivo para ser capaz de ejecutar de esta manera:./test.rb
xamenrax

191

No reinventes la rueda; echa un vistazo a la biblioteca OptionParser de Ruby .

Ofrece el análisis de indicadores / interruptores, parámetros con valores opcionales o requeridos, puede analizar listas de parámetros en una sola opción y puede generar su ayuda para usted.

Además, si alguna de su información que se pasa es bastante estática, eso no cambia entre ejecuciones, póngala en un archivo YAML que se analice. De esa manera, puede tener cosas que cambian cada vez en la línea de comandos, y cosas que cambian ocasionalmente configuradas fuera de su código. Esa separación de datos y código es buena para el mantenimiento.

Aquí hay algunas muestras para jugar:

require 'optparse'
require 'yaml'

options = {}
OptionParser.new do |opts|
  opts.banner = "Usage: example.rb [options]"

  opts.on('-n', '--sourcename NAME', 'Source name') { |v| options[:source_name] = v }
  opts.on('-h', '--sourcehost HOST', 'Source host') { |v| options[:source_host] = v }
  opts.on('-p', '--sourceport PORT', 'Source port') { |v| options[:source_port] = v }

end.parse!

dest_options = YAML.load_file('destination_config.yaml')
puts dest_options['dest_name']

Este es un archivo YAML de muestra si sus destinos son bastante estáticos:

--- 
dest_name: username@gmail.com
dest_host: imap.gmail.com
dest_port: 993
dest_ssl: true
dest_user: username@gmail.com
dest_pass: password

Esto le permitirá generar fácilmente un archivo YAML:

require 'yaml'

yaml = {
  'dest_name' => 'username@gmail.com',
  'dest_host' => 'imap.gmail.com',
  'dest_port' => 993,
  'dest_ssl'  => true,
  'dest_user' => 'username@gmail.com',
  'dest_pass' => 'password'
}

puts YAML.dump(yaml)

2
El enlace OptParse está muerto. Pruebe ruby-doc.org/stdlib-1.9.3/libdoc/optparse/rdoc/…
Casey el

77
Excelente respuesta; Puede valer la pena agregar que después de que se realiza el análisis de opciones, ARGVcontiene solo los operandos, si los hay (es decir, los argumentos restantes, que no son de opciones).
mklement0

27

Desafortunadamente, Ruby no admite mecanismos de paso como, por ejemplo, AWK:

> awk -v a=1 'BEGIN {print a}'
> 1

Significa que no puede pasar valores con nombre a su script directamente.

Usar las opciones de cmd puede ayudar:

> ruby script.rb val_0 val_1 val_2

# script.rb
puts ARGV[0] # => val_0
puts ARGV[1] # => val_1
puts ARGV[2] # => val_2

Ruby almacena todos los argumentos de cmd en la ARGVmatriz, el nombre del script se puede capturar utilizando la $PROGRAM_NAMEvariable.

La desventaja obvia es que depende del orden de los valores.

Si solo necesita modificadores booleanos, use la opción -sdel intérprete Ruby:

> ruby -s -e 'puts "So do I!" if $agreed' -- -agreed
> So do I!

Tenga en cuenta el --cambio, de lo contrario, Ruby se quejará de una opción inexistente -agreed, así que páselo como un cambio a su invocación de cmd. No lo necesita en el siguiente caso:

> ruby -s script_with_switches.rb -agreed
> So do I!

La desventaja es que se mete con variables globales y solo tiene valores lógicos verdadero / falso.

Puede acceder a valores desde variables de entorno:

> FIRST_NAME='Andy Warhol' ruby -e 'puts ENV["FIRST_NAME"]'
> Andy Warhol

Los inconvenientes están presentes aquí, debe configurar todas las variables antes de la invocación del script (solo para su proceso de ruby) o exportarlas (shells como BASH):

> export FIRST_NAME='Andy Warhol'
> ruby -e 'puts ENV["FIRST_NAME"]'

En el último caso, sus datos serán legibles para todos en la misma sesión de shell y para todos los subprocesos, lo que puede ser una grave implicación de seguridad.

Y al menos puede implementar un analizador de opciones usando getoptlong y optparse .

¡Feliz pirateo!


1

También puedes probar cliqr. Es bastante nuevo y en desarrollo activo. Pero hay versiones estables listas para ser utilizadas. Aquí está el repositorio de git: https://github.com/anshulverma/cliqr

Mire en la carpeta de ejemplo para tener una idea de cómo se puede usar.


0

Ejecute este código en la línea de comando e ingrese el valor de N:

N  = gets; 1.step(N.to_i, 1) { |i| print "hello world\n" }

0

A menos que sea el caso más trivial, solo hay una forma sensata de usar las opciones de línea de comandos en Ruby. Se llama docopt y se documenta aquí .

Lo que es sorprendente es su simplicidad. Todo lo que tiene que hacer es especificar el texto de "ayuda" para su comando. Lo que escriba allí será analizado automáticamente por la biblioteca ruby independiente (!).

Del ejemplo :

#!/usr/bin/env ruby
require 'docopt.rb'

doc = <<DOCOPT
Usage: #{__FILE__} --help
       #{__FILE__} -v...
       #{__FILE__} go [go]
       #{__FILE__} (--path=<path>)...
       #{__FILE__} <file> <file>

Try: #{__FILE__} -vvvvvvvvvv
     #{__FILE__} go go
     #{__FILE__} --path ./here --path ./there
     #{__FILE__} this.txt that.txt

DOCOPT

begin
  require "pp"
  pp Docopt::docopt(doc)
rescue Docopt::Exit => e
  puts e.message
end

La salida:

$ ./counted_example.rb -h
Usage: ./counted_example.rb --help
       ./counted_example.rb -v...
       ./counted_example.rb go [go]
       ./counted_example.rb (--path=<path>)...
       ./counted_example.rb <file> <file>

Try: ./counted_example.rb -vvvvvvvvvv
     ./counted_example.rb go go
     ./counted_example.rb --path ./here --path ./there
     ./counted_example.rb this.txt that.txt

$ ./counted_example.rb something else
{"--help"=>false,
 "-v"=>0,
 "go"=>0,
 "--path"=>[],
 "<file>"=>["something", "else"]}

$ ./counted_example.rb -v
{"--help"=>false, "-v"=>1, "go"=>0, "--path"=>[], "<file>"=>[]}

$ ./counted_example.rb go go
{"--help"=>false, "-v"=>0, "go"=>2, "--path"=>[], "<file>"=>[]}

¡Disfrutar!


0

Deberías probar console_runner gem. Esta gema hace que su código Ruby puro sea ejecutable desde la línea de comandos. Todo lo que necesita es agregar anotaciones YARD a su código:

# @runnable This tool can talk to you. Run it when you are lonely.
#   Written in Ruby.  
class MyClass

    def initialize
      @hello_msg = 'Hello' 
      @bye_msg = 'Good Bye' 
    end

    # @runnable Say 'Hello' to you.
    # @param [String] name Your name
    # @param [Hash] options options
    # @option options [Boolean] :second_meet Have you met before?
    # @option options [String] :prefix Your custom prefix
    def say_hello(name, options = {})
      second_meet = nil
      second_meet = 'Nice to see you again!' if options['second_meet']
      prefix = options['prefix']
      message = @hello_msg + ', '
      message += "#{prefix} " if prefix
      message += "#{name}. "
      message += second_meet if second_meet
      puts message
    end

end

Luego ejecútelo desde la consola:

$ c_run /projects/example/my_class.rb  say_hello -n John --second-meet --prefix Mr. 
-> Hello, Mr. John. Nice to see you again!

0

tl; dr

Sé que esto es antiguo, pero getoptlong no se mencionó aquí y es probable que hoy sea la mejor manera de analizar los argumentos de la línea de comandos.


Análisis de argumentos de línea de comando

Recomiendo mucho getoptlong . Es bastante fácil de usar y funciona de maravilla. Aquí hay un ejemplo extraído del enlace de arriba

require 'getoptlong'

opts = GetoptLong.new(
    [ '--help', '-h', GetoptLong::NO_ARGUMENT ],
    [ '--repeat', '-n', GetoptLong::REQUIRED_ARGUMENT ],
    [ '--name', GetoptLong::OPTIONAL_ARGUMENT ]
)

dir = nil
name = nil
repetitions = 1
opts.each do |opt, arg|
    case opt
        when '--help'
            puts <<-EOF
hello [OPTION] ... DIR

-h, --help:
     show help

--repeat x, -n x:
     repeat x times

--name [name]:
     greet user by name, if name not supplied default is John

DIR: The directory in which to issue the greeting.
            EOF
        when '--repeat'
            repetitions = arg.to_i
        when '--name'
            if arg == ''
                name = 'John'
            else
                name = arg
            end
    end
end

if ARGV.length != 1
    puts "Missing dir argument (try --help)"
    exit 0
end

dir = ARGV.shift

Dir.chdir(dir)
for i in (1..repetitions)
    print "Hello"
    if name
        print ", #{name}"
    end
    puts
end

Puedes llamarlo así ruby hello.rb -n 6 --name -- /tmp

¿Qué está tratando de hacer OP?

En este caso, creo que la mejor opción es usar archivos YAML como se sugiere en esta respuesta

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.