Handling CLI arguments with ARGV
In Ruby, we can access command-line arguments via the ARGV array. This allows us to create simple command-line interfaces (CLIs) for our Ruby scripts:
puts "Hello, #{ARGV.first}!"
When we run this script with ruby cli.rb Alice, it will output:
Hello, Alice!
Ok, so all programming languages provide some way to access command-line arguments. Why am I excited about Ruby in particular?
Mostly it comes down to my love of Ruby's Array API, and ARGV being an array means we can use all of those familiar methods to handle our arguments. A simple demonstration:
help = ARGV.delete("--help")
if ARGV.empty?
puts "Usage: cli.rb [--help] [args...]"
exit
end
COMMANDS = {
"greet" => {
"description" => "Greet someone",
"usage" => "cli.rb greet ",
"action" => ->(name) { puts "Hello, #{name}!" }
},
"add" => {
"description" => "Add two numbers",
"usage" => "cli.rb add ",
"action" => ->(x, y) { puts x.to_i + y.to_i }
}
}.freeze
command_name = ARGV.shift
command = COMMANDS[command_name]
abort "ERROR: Unknown command - #{command_name}" unless command
if help
puts "Command: #{command_name}"
puts command["description"]
puts "Usage: #{command["usage"]}"
exit
end
command["action"].call(*ARGV)
Note how naturally we can make use of methods like delete, shift and empty?, as well as the splat operator (*ARGV), all curtesy of basic array handling.
Example usage:
$ ruby cli.rb
Usage: cli.rb <command> [--help] [args...]
$ ruby cli.rb greet --help
Command: greet
Greet someone
Usage: cli.rb greet <name>
$ ruby cli.rb greet Alice
Hello, Alice!
$ ruby cli.rb add --help
Command: add
Add two numbers
Usage: cli.rb add <x> <y>
$ ruby cli.rb add 2 3
5
Not bad for such a tiny amount of code!
The alias no one knows about
While writing this article, I was surprised to discover that ARGV has an alias: $*.
This is a reference to POSIX-style shells where $* expands to all the positional parameters.
I've never seen this alias used in the wild, but hey, the more you know! 🌈
History
In the very early pre-release versions of Ruby, CLI arguments were exposed via $ARGV, with the $* alias already present.
The modern ARGV constant arrived before Ruby 1.0. By Ruby 0.99, $ARGV had been replaced by ARGV, while $* remained as an alias.
The name is derived from C's argv, short for "argument vector", used in the classic main(int argc, char **argv) signature. But Ruby may also have been encouraged by Perl, which exposes CLI arguments as @ARGV.