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

3 Answers 3

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]
Sign up to request clarification or add additional context in comments.

2 Comments

Thnx. Christian . I am trying to call it from shell and not irb. Looks like eval is the only option ..
Well, you can use the last two lines of code to accomplish that, since you get it as a string.
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

2 Comments

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: You are using an old version of Ruby. The new hash syntax was introduced in Ruby 1.9.0.
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

4 Comments

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
Adding " and escaping them did the trick . jruby test.rb [\"path1\",\"path2\"], 3, [\"name1\", \"name2\"], 8 .. Thnx, this worked for me !
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.
And this eval("foo " + ARGV.join(" ").gsub(/([\w\\\/])/, '"\1"')) if you want to include \ and / :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.