ส่งผ่านตัวแปรไปยังสคริปต์ Ruby ผ่านบรรทัดคำสั่ง


275

ฉันติดตั้ง RubyInstaller บน Windows แล้วและฉันใช้IMAP Sync อยู่แต่ฉันต้องใช้เพื่อซิงค์บัญชีหลายร้อยบัญชี ถ้าฉันสามารถส่งตัวแปรเหล่านี้ไปยังมันผ่านทางบรรทัดคำสั่งฉันสามารถทำให้กระบวนการทั้งหมดดีขึ้นโดยอัตโนมัติ

# 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
คุณอาจต้องการที่จะต้องพิจารณาแก้ไขคำถามนี้เป็นที่นิยมเป็นจริงคำถาม
not2qubit

คำตอบ:


465

บางสิ่งเช่นนี้

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

แล้วก็

$ ./test.rb "test1 test2"

หรือ

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

84
ฉันต้องการจะชี้ให้เห็นอย่างชัดเจนว่า ARGV [0] ไม่ได้ชี้ไปที่ชื่อโปรแกรมเช่นเดียวกับภาษาอื่น ๆ ในการรับชื่อโปรแกรมดูstackoverflow.com/questions/4834821/…
Sander Mertens

3
`` test1 test2 'ไม่ใช่อาร์กิวเมนต์เดียวใช่หรือไม่
wuliwong

คุณต้องเพิ่ม#!/usr/bin/env rubyด้านบนของ.rbไฟล์เพื่อให้สามารถเรียกใช้เช่นนี้:./test.rb
xamenrax

191

อย่าประดิษฐ์ล้อใหม่ ตรวจสอบทับทิมวิธีเย็นOptionParserห้องสมุด

มันมีการแยกวิเคราะห์ของธง / สวิทช์พารามิเตอร์ที่มีค่าหรือจำเป็นต้องใช้สามารถแยกรายการพารามิเตอร์เป็นตัวเลือกเดียวและสามารถสร้างความช่วยเหลือของคุณ

นอกจากนี้หากข้อมูลใด ๆ ของคุณที่ถูกส่งเข้ามานั้นค่อนข้างคงที่ซึ่งจะไม่เปลี่ยนแปลงระหว่างการทำงานให้ใส่ข้อมูลลงในไฟล์ YAML ที่แยกวิเคราะห์ ด้วยวิธีนี้คุณสามารถมีสิ่งต่าง ๆ ที่เปลี่ยนแปลงได้ตลอดเวลาในบรรทัดคำสั่งและสิ่งต่าง ๆ ที่เปลี่ยนแปลงในบางครั้งมีการกำหนดค่านอกรหัสของคุณ การแยกข้อมูลและรหัสนั้นดีสำหรับการบำรุงรักษา

นี่คือตัวอย่างที่จะเล่นกับ:

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

นี่คือไฟล์ 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

สิ่งนี้จะช่วยให้คุณสร้างไฟล์ 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
ลิงก์ OptParse ไม่ทำงาน ลองruby-doc.org/stdlib-1.9.3/libdoc/optparse/rdoc/ …
Casey

7
คำตอบที่ยอดเยี่ยม; อาจมีค่าเพิ่มที่หลังจากตัวเลือกการแยกวิเคราะห์เสร็จแล้วARGVมีเพียงตัวถูกดำเนินการถ้ามี (นั่นคือข้อโต้แย้งที่เหลือตัวเลือกที่ไม่ใช่ตัวเลือก)
mklement0

27

น่าเสียดายที่ Ruby ไม่สนับสนุนกลไกการส่งต่อเช่น AWK:

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

หมายความว่าคุณไม่สามารถส่งค่าที่ตั้งชื่อไปยังสคริปต์ของคุณโดยตรง

การใช้ตัวเลือก cmd อาจช่วยได้:

> 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 เก็บอาร์กิวเมนต์ cmd ทั้งหมดในARGVอาร์เรย์ชื่อสคริปต์สามารถถูกจับได้โดยใช้$PROGRAM_NAMEตัวแปร

ข้อเสียที่ชัดเจนคือคุณต้องพึ่งพาลำดับของค่า

หากคุณต้องการสวิตช์บูลีนเท่านั้นให้ใช้ตัวเลือก-sของตัวแปล Ruby:

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

โปรดทราบ--สวิตช์มิฉะนั้น Ruby จะบ่นเกี่ยวกับตัวเลือกที่ไม่มีอยู่-agreedดังนั้นให้ส่งผ่านเป็นสวิตช์ไปยังคำสั่ง cmd ของคุณ คุณไม่จำเป็นต้องใช้ในกรณีต่อไปนี้:

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

ข้อเสียคือคุณยุ่งกับตัวแปรทั่วโลกและมีค่าตรรกะจริง / เท็จเท่านั้น

คุณสามารถเข้าถึงค่าจากตัวแปรสภาพแวดล้อม:

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

มีข้อเสียอยู่ที่นี่คุณต้องตั้งค่าตัวแปรทั้งหมดก่อนที่จะเรียกใช้สคริปต์ (สำหรับกระบวนการทับทิมของคุณ) หรือส่งออก (เชลล์เช่น BASH):

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

ในกรณีหลังข้อมูลของคุณจะสามารถอ่านได้สำหรับทุกคนในเชลล์เซสชั่นเดียวกันและสำหรับกระบวนการย่อยทั้งหมดซึ่งอาจส่งผลต่อความปลอดภัยอย่างรุนแรง

และอย่างน้อยคุณสามารถดำเนินการแยกวิเคราะห์โดยใช้getoptlongและoptparse

แฮ็คมีความสุข!


1

cliqrนอกจากนี้คุณยังสามารถลอง มันค่อนข้างใหม่และในการพัฒนาที่ใช้งานอยู่ แต่มีการเผยแพร่ที่เสถียรพร้อมใช้งาน นี่คือ repo คอมไพล์: https://github.com/anshulverma/cliqr

ดูในโฟลเดอร์ตัวอย่างเพื่อรับแนวคิดเกี่ยวกับวิธีการใช้งาน



0

เว้นแต่จะเป็นกรณีที่ไม่สำคัญที่สุดมีเพียงวิธีเดียวเท่านั้นที่จะใช้ตัวเลือกบรรทัดคำสั่งใน Ruby มันถูกเรียกว่าdocoptและจัดทำเอกสารที่นี่

สิ่งที่น่าทึ่งกับมันคือความเรียบง่าย สิ่งที่คุณต้องทำคือระบุข้อความ "ช่วย" สำหรับคำสั่งของคุณ สิ่งที่คุณเขียนจะมีการแยกวิเคราะห์อัตโนมัติโดยห้องสมุดทับทิมแบบสแตนด์อโลน (!)

จากตัวอย่าง :

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

ผลลัพธ์:

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

สนุก!


0

คุณควรลองใช้console_runner gem อัญมณีนี้ทำให้โค้ดทับทิมบริสุทธิ์ของคุณสามารถเรียกใช้ได้จากบรรทัดคำสั่ง สิ่งที่คุณต้องมีก็คือการเพิ่มบันทึกย่อYARDให้กับรหัสของคุณ:

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

จากนั้นเรียกใช้จากคอนโซล:

$ 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

ฉันรู้ว่านี่เก่า แต่getoptlongไม่ได้กล่าวถึงที่นี่และอาจเป็นวิธีที่ดีที่สุดในการแยกอาร์กิวเมนต์บรรทัดคำสั่งวันนี้


แยกอาร์กิวเมนต์บรรทัดคำสั่ง

ผมขอแนะนำgetoptlong มันใช้งานง่ายและมีเสน่ห์ นี่คือตัวอย่างที่ดึงมาจากลิงค์ด้านบน

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

คุณสามารถโทรแบบนี้ได้ ruby hello.rb -n 6 --name -- /tmp

OP กำลังพยายามทำอะไร

ในกรณีนี้ฉันคิดว่าตัวเลือกที่ดีที่สุดคือการใช้ไฟล์ YAML ตามที่แนะนำในคำตอบนี้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.