2

I have a ruby script that takes two inputs for ARGV. The second input is an array of files. I'm having trouble iterating through the file array passed to ARGV. Here is what I have so far:

arg1, FILES = ARGV

FILES.each do |fname| 
    #do something with fname 
end 

I'm running my script from the command line like this:

ruby myScript.rb arg1 ['path/to/file1.jpg', '/path/to/file2.jpg'] 

And I'm getting the following error:

zsh: bad pattern: [path/to/file1.jpg,

Enclosing the array argument in single quotes like this:

ruby myScript.rb arg1 '['path/to/file1.jpg', '/path/to/file2.jpg']'

Produces a different error, as it interprets it as a String rather than array.

How can I accomplish this correctly?

ndnenkov
  • 35,425
  • 9
  • 72
  • 104
cvoep28
  • 423
  • 5
  • 9
  • 21

4 Answers4

2

Use

arg1, *FILES = ARGV

and don't place any brackets or commas during invocation:

ruby myScript.rb arg1 file1 file2 file3


EDIT: If you want to add another argument, you can do:
arg1, arg2, *FILES = ARGV

or

arg1, *FILES, arg2 = ARGV
ndnenkov
  • 35,425
  • 9
  • 72
  • 104
  • Does the asterisk denote an array? Also, what if a third argument is added after files? – cvoep28 Sep 10 '15 at 19:33
  • 1
    @FionaCat86, the `*` will say *"put the first argument in `arg1` and the rest in `FILES`"*. So `FILES` will be an array. If you want to add another argument, add it after `arg1`. Note that CLIs don't have a concept of *"array"* in general, this is not something Ruby specific. You can parse arguments enclosed in `[]`, but there is no out of the box solution for it. – ndnenkov Sep 10 '15 at 19:36
  • I ran this and it produced error "undefined method `each' for "path/to/file1.jpg":String (NoMethodError)" Seems like it's just looking at the first string rather than the array as a whole? – cvoep28 Sep 10 '15 at 19:42
  • @FionaCat86, I get this if I remove the `*`. It works just fine if it's there. – ndnenkov Sep 10 '15 at 19:45
1

You can't pass an array as a command-line argument. All arguments are passed as strings.

But given your code, you could just pass the arguments like this:

$ ruby myScript.rb arg1 path/to/file1.jpg /path/to/file2.jpg

And then, change your first line of code to this:

arg1, *FILES = ARGV

And after, arg1 = 'arg1' and FILES = ['path/to/file1.jpg', 'path/to/file2.jpg'].

mipadi
  • 398,885
  • 90
  • 523
  • 479
1

You can either split manually, e.g. arg, arr = ARGV[0], ARGV[1..-1] or use the splat operator arg, *arr = ARGV

dimid
  • 7,285
  • 1
  • 46
  • 85
0
arg1, _files = ARGV
files = eval(_files)
files.each { |f| ... }

But there are reasons to not use eval (see Is 'eval' supposed to be nasty?).

You might pass the files list as a json string and then do JSON.parse on it to be safer, e.g.:

require 'json'
arg1, _files = ARGV
files = JSON.parse(_files)
files.each { |f| ... }

#> ruby myScript.rb arg1 '["path/to/file1.jpg", "/path/to/file2.jpg"]'
Community
  • 1
  • 1
Jacob Brown
  • 7,221
  • 4
  • 30
  • 50