Lewati variabel ke skrip Ruby melalui baris perintah

275

Saya telah menginstal RubyInstaller di Windows dan saya menjalankan IMAP Sync tetapi saya harus menggunakannya untuk menyinkronkan ratusan akun. Jika saya bisa meneruskan variabel-variabel ini ke sana melalui baris perintah saya bisa mengotomatiskan seluruh proses dengan lebih baik.

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

# Destination server connection info.
DEST_NAME = '[email protected]'
DEST_HOST = 'imap.gmail.com'
DEST_PORT = 993
DEST_SSL  = true
DEST_USER = '[email protected]'
DEST_PASS = 'password'
Kilat
sumber
1
Anda mungkin ingin mempertimbangkan untuk mengedit pertanyaan populer ini menjadi pertanyaan aktual .
not2qubit

Jawaban:

465

Sesuatu seperti ini:

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

kemudian

$ ./test.rb "test1 test2"

atau

v1 = ARGV[0]
v2 = ARGV[1]
puts v1       #prints test1
puts v2       #prints test2
demo
sumber
84
Saya ingin secara eksplisit menunjukkan bahwa ARGV [0] tidak menunjuk ke nama program, seperti beberapa bahasa lainnya. Untuk mendapatkan nama program, lihat stackoverflow.com/questions/4834821/…
Sander Mertens
3
Bukankah `" test1 test2 "hanya satu argumen?
wuliwong
Anda perlu menambahkan #!/usr/bin/env rubydi atas .rbfile untuk dapat menjalankannya seperti ini:./test.rb
xamenrax
191

Jangan menemukan kembali roda; lihat pustaka OptionParser Ruby yang keren .

Ia menawarkan penguraian flag / switch, parameter dengan nilai opsional atau yang diperlukan, dapat mengurai daftar parameter menjadi satu opsi dan dapat menghasilkan bantuan Anda untuk Anda.

Juga, jika ada informasi Anda yang dilewatkan cukup statis, itu tidak berubah antara berjalan, memasukkannya ke file YAML yang diuraikan. Dengan begitu Anda dapat memiliki hal-hal yang berubah setiap kali pada baris perintah, dan hal-hal yang berubah sesekali dikonfigurasi di luar kode Anda. Pemisahan data dan kode itu bagus untuk pemeliharaan.

Berikut beberapa contoh untuk dimainkan:

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

Ini adalah contoh file YAML jika tujuan Anda cukup statis:

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

Ini akan membuat Anda dengan mudah menghasilkan file YAML:

require 'yaml'

yaml = {
  'dest_name' => '[email protected]',
  'dest_host' => 'imap.gmail.com',
  'dest_port' => 993,
  'dest_ssl'  => true,
  'dest_user' => '[email protected]',
  'dest_pass' => 'password'
}

puts YAML.dump(yaml)
Manusia Timah
sumber
2
Tautan OptParse mati. Coba ruby-doc.org/stdlib-1.9.3/libdoc/optparse/rdoc/…
Casey
7
Jawaban luar biasa; mungkin perlu ditambahkan bahwa setelah penguraian opsi selesai, ARGVhanya berisi operan, jika ada (yaitu, argumen yang tersisa, opsi NON-opsi).
mklement0
27

Sayangnya, Ruby tidak mendukung mekanisme passing seperti misalnya AWK:

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

Ini berarti Anda tidak dapat meneruskan nilai yang disebutkan ke dalam skrip Anda secara langsung.

Menggunakan opsi cmd dapat membantu:

> 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 menyimpan semua argumen cmd dalam ARGVarray, nama script itu sendiri dapat ditangkap menggunakan $PROGRAM_NAMEvariabel.

Kerugian yang jelas adalah bahwa Anda bergantung pada urutan nilai.

Jika Anda hanya perlu sakelar Boolean gunakan opsi -sjuru bahasa Ruby:

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

Harap perhatikan --sakelar, jika tidak, Ruby akan mengeluh tentang opsi yang tidak ada -agreed, jadi serahkan sebagai sakelar ke cmd invokation Anda. Anda tidak membutuhkannya dalam kasus berikut:

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

Kerugiannya adalah bahwa Anda mengacaukan variabel global dan hanya memiliki nilai true / false logis.

Anda dapat mengakses nilai dari variabel lingkungan:

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

Kerugian hadir di sini untuk, Anda harus mengatur semua variabel sebelum permintaan skrip (hanya untuk proses ruby ​​Anda) atau untuk mengekspornya (kulit seperti BASH):

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

Dalam kasus terakhir, data Anda akan dapat dibaca untuk semua orang di sesi shell yang sama dan untuk semua subproses, yang bisa menjadi implikasi keamanan yang serius.

Dan setidaknya Anda dapat menerapkan parser pilihan menggunakan getoptlong dan optparse .

Selamat melakukan peretasan!

Andrei Beliankou
sumber
1

Anda juga bisa mencobanya cliqr. Cukup baru dan dalam pengembangan aktif. Tetapi ada rilis stabil yang siap digunakan. Inilah repo git: https://github.com/anshulverma/cliqr

Lihatlah ke dalam folder contoh untuk mendapatkan ide tentang bagaimana itu dapat digunakan.

nuaavee
sumber
0

Jalankan kode ini pada baris perintah dan masukkan nilai N:

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

Kecuali itu adalah kasus yang paling sepele, hanya ada satu cara yang waras untuk menggunakan opsi baris perintah di Ruby. Itu disebut docopt dan didokumentasikan di sini .

Apa yang luar biasa dengan itu, adalah kesederhanaannya. Yang harus Anda lakukan adalah menentukan teks "bantuan" untuk perintah Anda. Apa yang Anda tulis di sana akan di-parsing secara otomatis oleh perpustakaan ruby mandiri !

Dari contoh :

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

Hasil:

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

Nikmati!

not2qubit
sumber
0

Anda harus mencoba permata console_runner . Permata ini membuat kode Ruby murni Anda dapat dieksekusi dari baris perintah. Yang Anda butuhkan hanyalah menambahkan YARD annotations ke kode Anda:

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

Kemudian jalankan dari konsol:

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

tl; dr

Saya tahu ini sudah tua, tetapi getoptlong tidak disebutkan di sini dan mungkin cara terbaik untuk mengurai argumen baris perintah hari ini.


Mengurai argumen baris perintah

Saya sangat merekomendasikan getoptlong . Ini cukup mudah digunakan dan bekerja seperti pesona. Berikut adalah contoh yang diambil dari tautan di atas

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

Anda bisa menyebutnya seperti ini ruby hello.rb -n 6 --name -- /tmp

Apa yang OP coba lakukan

Dalam hal ini saya pikir pilihan terbaik adalah menggunakan file YAML seperti yang disarankan dalam jawaban ini

Redithion
sumber