Übergeben Sie Variablen über die Befehlszeile an das Ruby-Skript


279

Ich habe RubyInstaller unter Windows installiert und verwende IMAP Sync , muss es jedoch verwenden, um Hunderte von Konten zu synchronisieren. Wenn ich diese Variablen über die Befehlszeile an sie übergeben könnte, könnte ich den gesamten Prozess besser automatisieren.

# 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
Möglicherweise möchten Sie diese beliebte Frage in eine tatsächliche Frage umwandeln .
not2qubit

Antworten:


475

Etwas wie das:

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

dann

$ ./test.rb "test1 test2"

oder

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

84
Ich möchte ausdrücklich darauf hinweisen, dass ARGV [0] nicht wie einige andere Sprachen auf den Programmnamen verweist. Den Programmnamen finden Sie unter stackoverflow.com/questions/4834821/…
Sander Mertens

3
Ist "test1 test2" nicht nur ein einziges Argument?
Wuliwong

Sie müssen #!/usr/bin/env rubyoben auf der .rbDatei hinzufügen , um sie wie ./test.rb
folgt ausführen

193

Erfinde das Rad nicht neu. Schauen Sie sich Rubys coole OptionParser- Bibliothek an.

Es bietet das Parsen von Flags / Switches, Parametern mit optionalen oder erforderlichen Werten, kann Parameterlisten in einer einzigen Option analysieren und Ihre Hilfe für Sie generieren.

Wenn eine Ihrer übergebenen Informationen ziemlich statisch ist und sich zwischen den Läufen nicht ändert, fügen Sie sie in eine YAML-Datei ein, die analysiert wird. Auf diese Weise können Sie Dinge, die sich jedes Mal in der Befehlszeile ändern, und Dinge, die sich gelegentlich ändern, außerhalb Ihres Codes konfigurieren. Diese Trennung von Daten und Code ist gut für die Wartung.

Hier sind einige Beispiele zum Spielen:

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

Dies ist eine Beispiel-YAML-Datei, wenn Ihre Ziele ziemlich statisch sind:

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

Auf diese Weise können Sie auf einfache Weise eine YAML-Datei erstellen:

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
OptParse-Link ist tot. Versuchen Sie ruby-doc.org/stdlib-1.9.3/libdoc/optparse/rdoc/…
Casey

7
Ausgezeichnete Antwort; Es kann sinnvoll sein, hinzuzufügen, dass nach dem Parsen der Optionen ARGVnur die Operanden enthalten, sofern vorhanden (dh die verbleibenden Argumente ohne Option).
mklement0

29

Leider unterstützt Ruby keinen Übergabemechanismus wie z. B. AWK:

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

Dies bedeutet, dass Sie benannte Werte nicht direkt an Ihr Skript übergeben können.

Die Verwendung von cmd-Optionen kann helfen:

> 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 speichert alle cmd-Argumente im ARGVArray. Der Skriptname selbst kann mithilfe der $PROGRAM_NAMEVariablen erfasst werden .

Der offensichtliche Nachteil ist, dass Sie von der Reihenfolge der Werte abhängen.

Wenn Sie nur Boolesche Schalter benötigen, verwenden Sie die Option -sdes Ruby-Interpreters:

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

Bitte beachten Sie den --Schalter, andernfalls beschwert sich Ruby über eine nicht vorhandene Option -agreed. Übergeben Sie ihn daher als Schalter an Ihren cmd-Aufruf. Sie brauchen es im folgenden Fall nicht:

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

Der Nachteil ist, dass Sie mit globalen Variablen herumspielen und nur logische True / False-Werte haben.

Sie können über Umgebungsvariablen auf Werte zugreifen:

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

Hierbei gibt es Nachteile: Sie müssen alle Variablen vor dem Skriptaufruf festlegen (nur für Ihren Ruby-Prozess) oder sie exportieren (Shells wie BASH):

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

Im letzteren Fall sind Ihre Daten für alle in derselben Shell-Sitzung und für alle Unterprozesse lesbar, was schwerwiegende Auswirkungen auf die Sicherheit haben kann.

Und zumindest können Sie einen Optionsparser mit getoptlong und optparse implementieren .

Viel Spaß beim Hacken!


1

Sie können auch ausprobieren cliqr. Es ist ziemlich neu und in aktiver Entwicklung. Es gibt jedoch stabile Versionen, die verwendet werden können. Hier ist das Git-Repo: https://github.com/anshulverma/cliqr

Schauen Sie in den Beispielordner, um eine Vorstellung davon zu bekommen, wie er verwendet werden kann.


0

Führen Sie diesen Code in der Befehlszeile aus und geben Sie den Wert von N ein:

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

0

Sofern dies nicht der trivialste Fall ist, gibt es in Ruby nur eine vernünftige Möglichkeit, Befehlszeilenoptionen zu verwenden. Es heißt docopt und ist hier dokumentiert .

Was daran erstaunlich ist, ist die Einfachheit. Sie müssen lediglich den Hilfetext für Ihren Befehl angeben. Was Sie dort schreiben, wird dann von der eigenständigen (!) Ruby-Bibliothek automatisch analysiert .

Aus dem Beispiel :

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

Die Ausgabe:

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

Genießen!


0

Sie sollten console_runner gem versuchen . Dieses Juwel macht Ihren reinen Ruby-Code über die Befehlszeile ausführbar. Sie müssen lediglich YARD- Anmerkungen zu Ihrem Code hinzufügen :

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

Führen Sie es dann von der Konsole aus:

$ 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

Ich weiß, dass dies alt ist, aber getoptlong wurde hier nicht erwähnt und es ist wahrscheinlich der beste Weg, um heute Befehlszeilenargumente zu analysieren.


Analysieren von Befehlszeilenargumenten

Ich empfehle getoptlong . Es ist ziemlich einfach zu bedienen und wirkt wie ein Zauber. Hier ist ein Beispiel aus dem obigen Link

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

Sie können es so nennen ruby hello.rb -n 6 --name -- /tmp

Was OP versucht zu tun

In diesem Fall ist es meiner Meinung nach die beste Option, YAML-Dateien zu verwenden, wie in dieser Antwort vorgeschlagen

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.