3

I am trying to pass an array to a ruby script from a command line and facing some issue.

Here is the problem:

require 'pp'

def foo(arr1, var, arr2, var2)
  puts arr1.class
  pp arr1
  pp arr1[0]
  puts arr2.class
  pp arr2
  pp arr2[0]
end

foo [1, 2], 3, [5, 6], 8

Here is the output:

Array
[1, 2]
1
Array
[5, 6]
5

All is fine so far. Now I change my script to accept argument from the command line:

require 'pp'

def foo(arr1,var)
  puts arr1.class
  pp arr1
  pp arr1[0]
end
foo ARGV[0],3

Here is the output:

jruby test.rb [1, 2], 3, [5, 6], 8
String
"[1,"
91
String
"2],"
50

As you can see, the array gets passed as a string and arr[0] basically prints the ascii value.

So the question is how do I pass an array from the command line , hopefully in one line. Also I believe this question is related to all shell invocations than just ruby ?

I am using bash shell.

Update: Just updated the question to indicate that there can be multiple arrays at different positions

codeObserver
  • 6,521
  • 16
  • 76
  • 121

3 Answers3

2

Here's a list of ways to accomplish this. Stay away from the eval-based solutions. My favorite (though I don't know ruby, but this is my favorite:

irb(main):001:0> s = "[5,3,46,6,5]"
=> "[5,3,46,6,5]"
irb(main):002:0> a = s.scan( /\d+/ )
=> ["5", "3", "46", "6", "5"]
irb(main):003:0> a.map!{ |s| s.to_i }
=> [5, 3, 46, 6, 5]
Christian Mann
  • 8,030
  • 5
  • 41
  • 51
2

The arguments will always come in as string, you need to find a way to turn them into the format you want, in your example an array of values, followed by a single value. I suggest using trollop for this, to take the heavy lifting out of dealing with the arguments. It can accept multi-value arguments, e.g.

require 'trollop'

opts = Trollop.options do 
    opt :array, 'an array', type: :ints
    opt :val, 'a value', type: :int
end

puts "array: #{opts[:array].inspect}"
puts "val: #{opts[:val].inspect}"

Then you can do:

$ ruby test.rb -a 1 2 -v 3
array: [1, 2]
val: 3

And extra nice:

$ ruby test.rb --help
Options:
 --array, -a <i+>:   an array
 --val, -v <i>:   a value
 --help, -h:   Show this message
Jon M
  • 11,669
  • 3
  • 41
  • 47
  • Thnx Jon. This looks like an interesting option. However I get some syntax error and doc doesnt clearly explain my option. ========== syntax error, unexpected ':' opt :array, 'an array', type: :ints ========= . Also I updated my question to make it more clear – codeObserver Mar 08 '12 at 08:33
  • @codeObserver: You are using an old version of Ruby. The new hash syntax was introduced in Ruby 1.9.0. – Jörg W Mittag Mar 08 '12 at 10:06
0

You can use eval although you might open a security hole:

require 'pp'

def foo(arr1, var, arr2, var2)
  puts arr1.class
  pp arr1
  pp arr1[0]
  puts arr2.class
  pp arr2
  pp arr2[0]
end

eval("foo " + ARGV.join(" "))

Result

Array
[1, 2]
1
Array
[5, 6]
5

Hope it helps

Edu
  • 1,949
  • 1
  • 16
  • 18
  • Thanx Edu. The array I am passing is an array of string, file paths to be specific. Would really appreciate if you can give the correct syntax to pass an array of string , something like: jruby test.rb ["path1","path2"], 3, ["name1", "name2"], 8 – codeObserver Mar 08 '12 at 18:41
  • Adding " and escaping them did the trick . jruby test.rb [\"path1\",\"path2\"], 3, [\"name1\", \"name2\"], 8 .. Thnx, this worked for me ! – codeObserver Mar 08 '12 at 19:09
  • Hi codeObserver, you could change the eval to this: eval("foo " + ARGV.join(" ").gsub(/(\w+)/,'"\1"')) so you don't need to escape passing the arguments. – Edu Mar 08 '12 at 21:53
  • And this eval("foo " + ARGV.join(" ").gsub(/([\w\\\/])/, '"\1"')) if you want to include \ and / :-) – Edu Mar 08 '12 at 21:57