Passer des variables au script Ruby via la ligne de commande


275

J'ai installé RubyInstaller sur Windows et j'exécute IMAP Sync mais je dois l'utiliser pour synchroniser des centaines de comptes. Si je pouvais lui transmettre ces variables via la ligne de commande, je pourrais mieux automatiser l'ensemble du processus.

# 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
Vous voudrez peut-être envisager de modifier cette question populaire en une question réelle .
not2qubit

Réponses:


465

Quelque chose comme ça:

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

puis

$ ./test.rb "test1 test2"

ou

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

84
Je voudrais souligner explicitement que ARGV [0] ne pointe pas vers le nom du programme, comme le font d'autres langues. Pour obtenir le nom du programme, voir stackoverflow.com/questions/4834821/…
Sander Mertens

3
"Test1 test2" n'est-il pas un seul argument?
wuliwong

Vous devez ajouter #!/usr/bin/env rubyen haut du .rbfichier pour pouvoir l'exécuter comme ceci:./test.rb
xamenrax

191

Ne réinventez pas la roue; consultez la bibliothèque OptionParser très cool de Ruby .

Il propose l'analyse des indicateurs / commutateurs, des paramètres avec des valeurs facultatives ou obligatoires, peut analyser les listes de paramètres en une seule option et peut générer votre aide pour vous.

De plus, si l'une de vos informations transmises est assez statique, cela ne change pas entre les exécutions, placez-la dans un fichier YAML qui est analysé. De cette façon, vous pouvez avoir des choses qui changent à chaque fois sur la ligne de commande, et des choses qui changent parfois configurées en dehors de votre code. Cette séparation des données et du code est agréable pour la maintenance.

Voici quelques exemples pour jouer avec:

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']

Voici un exemple de fichier YAML si vos destinations sont assez statiques:

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

Cela vous permettra de générer facilement un fichier 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
Le lien OptParse est mort. Essayez ruby-doc.org/stdlib-1.9.3/libdoc/optparse/rdoc/…
Casey

7
Excellente réponse; peut être utile d'ajouter qu'après l'analyse des options, ARGVne contient que les opérandes, le cas échéant (c'est-à-dire les arguments NON-option restants).
mklement0

27

Malheureusement, Ruby ne prend pas en charge un tel mécanisme de passage comme par exemple AWK:

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

Cela signifie que vous ne pouvez pas passer directement des valeurs nommées dans votre script.

L'utilisation des options cmd peut aider:

> 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 stocke tous les arguments cmd dans le ARGVtableau, le nom de script lui-même peut être capturé à l'aide de la $PROGRAM_NAMEvariable.

L'inconvénient évident est que vous dépendez de l'ordre des valeurs.

Si vous n'avez besoin que de commutateurs booléens, utilisez l'option -sde l'interpréteur Ruby:

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

Veuillez noter le --commutateur, sinon Ruby se plaindra d'une option inexistante -agreed, alors passez-la comme commutateur à votre invocation cmd. Vous n'en avez pas besoin dans le cas suivant:

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

L'inconvénient est que vous jouez avec les variables globales et n'avez que des valeurs logiques vrai / faux.

Vous pouvez accéder aux valeurs des variables d'environnement:

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

Les inconvénients sont présents ici, vous devez définir toutes les variables avant l'invocation du script (uniquement pour votre processus ruby) ou les exporter (shells comme BASH):

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

Dans ce dernier cas, vos données seront lisibles pour tout le monde dans la même session shell et pour tous les sous-processus, ce qui peut être une grave implication pour la sécurité.

Et au moins, vous pouvez implémenter un analyseur d'options en utilisant getoptlong et optparse .

Bon piratage!


1

Vous pouvez également essayer cliqr. C'est assez nouveau et en développement actif. Mais il existe des versions stables prêtes à être utilisées. Voici le dépôt git: https://github.com/anshulverma/cliqr

Regardez dans le dossier d'exemple pour avoir une idée de la façon dont il peut être utilisé.


0

Exécutez ce code sur la ligne de commande et entrez la valeur de N:

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

0

À moins que ce ne soit le cas le plus trivial, il n'y a qu'une seule façon saine d'utiliser les options de ligne de commande dans Ruby. Il est appelé docopt et documenté ici .

Ce qui est étonnant, c'est sa simplicité. Il vous suffit de spécifier le texte "aide" de votre commande. Ce que vous y écrivez sera ensuite analysé automatiquement par la bibliothèque ruby autonome (!).

De l' exemple :

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

Le résultat:

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

Prendre plaisir!


0

Vous devriez essayer console_runner gem. Cette gemme rend votre code Ruby pur exécutable à partir de la ligne de commande. Tout ce dont vous avez besoin est d'ajouter des annotations YARD à votre code:

# @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

Exécutez-le ensuite à partir de la 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

Je sais que c'est vieux, mais getoptlong n'a pas été mentionné ici et c'est probablement la meilleure façon d'analyser les arguments de la ligne de commande aujourd'hui.


Analyse des arguments de ligne de commande

Je recommande fortement getoptlong . Il est assez facile à utiliser et fonctionne comme un charme. Voici un exemple extrait du lien ci-dessus

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

Vous pouvez l'appeler comme ça ruby hello.rb -n 6 --name -- /tmp

Ce que l'OP essaie de faire

Dans ce cas, je pense que la meilleure option est d'utiliser des fichiers YAML comme suggéré dans cette réponse

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.