Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ruby - how to correctly parse varying numbers of command line arguments

n00b question alert! here is the problem: I am creating a shell script that takes a minimum of 3 arguments: a string, a line number, and at least one file.

I've written a script that will accept EXACTLY 3 arguments, but I don't know how to handle multiple file name arguments.

here's the relevant parts of my code (skipping the writing back into the file etc):

#!/usr/bin/env ruby

the_string = ARGV[0] 
line_number = ARGV[1]
the_file = ARGV[2] 

def insert_script(str, line_n, file)
  f = file
  s = str
  ln = line_n.to_i

  if (File.file? f)
    read_in(f,ln,s)
  else 
    puts "false"
  end
end

def read_in(f,ln,s)
  lines = File.readlines(f)
  lines[ln] = s + "\n"
  return lines
end

# run it
puts insert_script(the_string, line_number, the_file)

now I know that it's easy to write a block that will iterate through ALL the arguments:

ARGV.each do |a|
   puts a 
end

but I need to ONLY loop through the args from ARGV[2] (the first file name) to the last file name.

I know there's got to be - at a minimum - at least one easy way to do this, but I just can't see what it is at the moment!

in any case - I'd be more than happy if someone can just point me to a tutorial or an example, I'm sure there are plenty out there - but I can't seem to find them.

thanks

like image 852
Bennett Von Bennett Avatar asked Feb 02 '12 01:02

Bennett Von Bennett


People also ask

How do I read command line arguments in ruby?

In your Ruby programs, you can access any command-line arguments passed by the shell with the ARGV special variable. ARGV is an Array variable which holds, as strings, each argument passed by the shell.

What does argv do in ruby?

In Ruby, ARGV is a constant defined in the Object class. It is an instance of the Array class and has access to all the array methods. Since it's an array, even though it's a constant, its elements can be modified and cleared with no trouble.

Which flag allows only one line of code executed?

The '-e' flag only allows a single line of code to be executed, but that does not mean that multiple '-e' flags cannot be placed on a single command line to execute multiple lines: ruby -e 'print "Hello Ruby!\


2 Answers

Would you consider using a helpful gem? Trollop is great for command line parsing because it automatically gives you help messages, long and short command-line switches, etc.

require 'trollop'

opts = Trollop::options do
  opt :string, "The string", :type => :string
  opt :line, "line number", :type => :int
  opt :file, "file(s)", :type => :strings
end

p opts 

When I call it "commandline.rb" and run it:

$ ruby commandline.rb --string "foo bar" --line 3 --file foo.txt bar.txt

{:string=>"foo bar", :line=>3, :file=>["foo.txt", "bar.txt"], :help=>false, :string_given=>true, :line_given=>true, :file_given=>true}
like image 131
Mark Thomas Avatar answered Oct 04 '22 22:10

Mark Thomas


If you modify the ARGV array to remove the elements you're no longer interested in treating as filenames, you can treat all remaining elements as filenames and iterate over their contents with ARGF.

That's a mouthful, a small example will demonstrate it more easily:

argf.rb:

#!/usr/bin/ruby

str = ARGV.shift
line = ARGV.shift

ARGF.each do |f|
    puts f
end
$ ./argf.rb one two argf.rb argf.rb 
#!/usr/bin/ruby

str = ARGV.shift
line = ARGV.shift

ARGF.each do |f|
    puts f
end
#!/usr/bin/ruby

str = ARGV.shift
line = ARGV.shift

ARGF.each do |f|
    puts f
end
$ 

There are two copies of the argf.rb file printed to the console because I gave the filename argf.rb twice on the command line. It was opened and iterated over once for each mention.

If you want to operate on the files as files, rather than read their contents, you can simply modify the ARGV array and then use the remaining elements directly.

like image 40
sarnold Avatar answered Oct 04 '22 23:10

sarnold