Passar variáveis ​​para o script Ruby via linha de comando


275

Instalei o RubyInstaller no Windows e estou executando o IMAP Sync, mas preciso usá-lo para sincronizar centenas de contas. Se eu pudesse passar essas variáveis ​​para ele via linha de comando, poderia automatizar melhor todo o processo.

# 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
Convém editar essa pergunta popular em uma pergunta real .
Not2qubit 17/09/2018

Respostas:


465

Algo assim:

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

então

$ ./test.rb "test1 test2"

ou

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

84
Eu gostaria de salientar explicitamente que o ARGV [0] não aponta para o nome do programa, como alguns outros idiomas. Para obter o nome do programa, ver stackoverflow.com/questions/4834821/...
Sander Mertens

3
O `" test1 test2 "não é apenas um argumento?
Wuliwong

Você precisa adicionar #!/usr/bin/env rubyno topo do .rbarquivo para poder executá-lo assim:./test.rb
xamenrax 15/09/19

191

Não reinvente a roda; confira o jeito legal de Ruby biblioteca OptionParser .

Oferece análise de sinalizadores / comutadores, parâmetros com valores opcionais ou necessários, pode analisar listas de parâmetros em uma única opção e pode gerar sua ajuda para você.

Além disso, se alguma das suas informações passadas for bastante estática, isso não muda entre as execuções, coloque-a em um arquivo YAML que é analisado. Dessa forma, você pode ter coisas que mudam toda vez na linha de comando e coisas que mudam ocasionalmente configuradas fora do seu código. Essa separação de dados e código é boa para manutenção.

Aqui estão alguns exemplos para brincar:

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 é um arquivo YAML de amostra se seus destinos forem 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

Isso permitirá que você gere facilmente um arquivo 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
O link OptParse está inoperante. Tente ruby-doc.org/stdlib-1.9.3/libdoc/optparse/rdoc/…
Casey

7
Excelente resposta; vale a pena acrescentar que, depois que a análise de opções for concluída, ARGVcontenha apenas os operandos, se houver (ou seja, os argumentos restantes NÃO de opção).
mklement0

27

Infelizmente, Ruby não suporta mecanismos de passagem como, por exemplo, AWK:

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

Isso significa que você não pode passar valores nomeados diretamente para o seu script.

O uso das opções de cmd pode ajudar:

> 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 armazena todos os argumentos de cmd na ARGVmatriz, o próprio nome do script pode ser capturado usando o comando$PROGRAM_NAME variável

A desvantagem óbvia é que você depende da ordem dos valores.

Se você precisar apenas de comutadores booleanos, use a opção -sdo interpretador Ruby:

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

Observe a --opção, caso contrário, Ruby reclamará de uma opção inexistente -agreed; portanto, passe-a como uma opção para sua invocação de cmd. Você não precisa disso no seguinte caso:

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

A desvantagem é que você mexe com variáveis ​​globais e possui apenas valores lógicos verdadeiros / falsos.

Você pode acessar valores de variáveis ​​de ambiente:

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

As desvantagens estão presentes aqui, você deve definir todas as variáveis ​​antes da chamada do script (apenas para o processo ruby) ou exportá-las (shells como BASH):

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

Neste último caso, seus dados serão legíveis para todos na mesma sessão de shell e para todos os subprocessos, o que pode ser uma séria implicação de segurança.

E pelo menos você pode implementar um analisador de opções usando getoptlong e optparse .

Feliz hacking!


1

Você também pode experimentar cliqr. É muito novo e em desenvolvimento ativo. Mas existem versões estáveis ​​prontas para serem usadas. Aqui está o repositório git: https://github.com/anshulverma/cliqr

Examine a pasta de exemplo para ter uma idéia de como ela pode ser usada.


0

Execute este código na linha de comandos e insira o valor de N:

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

0

A menos que seja o caso mais trivial, existe apenas uma maneira sensata de usar as opções de linha de comando no Ruby. É chamado docopt e documentado aqui .

O que é surpreendente com isso, é a simplicidade. Tudo o que você precisa fazer é especificar o texto "ajuda" do seu comando. O que você escreve lá será analisado automaticamente pela biblioteca ruby independente (!).

Do exemplo :

#!/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

A saída:

$ ./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>"=>[]}

Aproveitar!


0

Você deve tentar o console_runner gem. Essa gema torna seu código Ruby puro executável na linha de comando. Tudo que você precisa é adicionar anotações YARD ao seu 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

Em seguida, execute-o no console:

$ 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

Sei que isso é antigo, mas o getoptlong não foi mencionado aqui e é provavelmente a melhor maneira de analisar os argumentos da linha de comando hoje.


Analisando Argumentos da Linha de Comandos

Eu recomendo vivamente . É muito fácil de usar e funciona como um encanto. Aqui está um exemplo extraído do link acima

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

Você pode chamar assim ruby hello.rb -n 6 --name -- /tmp

O OP está tentando fazer

Nesse caso, acho que a melhor opção é usar arquivos YAML, conforme sugerido nesta resposta

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.