Question

Pass Command-Line Arguments to a Ruby Script

rubycommand-line

Question

I installed RubyInstaller on Windows and am using an IMAP synchronization Ruby script. I need to synchronize hundreds of accounts, so I want to supply the connection settings from the command line rather than editing the script for every account.

The script currently contains fixed values such as:

# Source server connection info.
SOURCE_NAME = 'username@example.com'
SOURCE_HOST = 'mail.example.com'
SOURCE_PORT = 143
SOURCE_SSL  = false
SOURCE_USER = 'username'
SOURCE_PASS = 'password'

# Destination server connection info.
DEST_NAME = 'username@gmail.com'
DEST_HOST = 'imap.gmail.com'
DEST_PORT = 993
DEST_SSL  = true
DEST_USER = 'username@gmail.com'
DEST_PASS = 'password'

How can these values be passed to the Ruby script when it is run from the command line so the process can be automated?

Short Answer

Ruby scripts receive command-line values through the ARGV array. For a small script, positional arguments can work; for many named settings, OptionParser makes commands clearer and easier to validate. Passwords should normally be supplied through environment variables or a protected configuration source rather than directly on the command line.

Concept

A Ruby program can receive input at the moment it starts. This lets one script work with different accounts, files, servers, or settings without changing its source code.

Ruby places command-line arguments in ARGV, an array of strings. For example, when you run:

ruby sync.rb alice@example.com mail.example.com

Ruby receives:

ARGV # => ["alice@example.com", "mail.example.com"]

This is useful for automation because a batch file, PowerShell script, scheduler, or another program can run the same Ruby script repeatedly with different input.

However, mail connection settings include passwords. A password written in a command can be exposed in shell history, process listings, logs, or scheduled-task definitions. Use environment variables, a secrets manager, or a file with restricted permissions for secrets whenever possible.

Also note that every item in ARGV is text. A port such as "993" must be converted with Integer, and a value such as "true" must be deliberately converted into a Boolean.

Mental Model

Think of a Ruby script as a form-processing machine.

  • The script file is the machine's fixed set of instructions.
  • Command-line arguments are values written on a form when the machine starts.
  • ARGV is the tray holding the submitted values.
  • OptionParser is the receptionist that reads labelled fields such as --source-host and rejects incomplete forms.
  • Environment variables are a separate, less visible envelope for sensitive details such as passwords.

Avoid relying on an argument's position when there are many settings. A command like sync.rb a b c d e f is difficult to read. Labelled options communicate what each value means.

Take Quiz

Syntax and Examples

Ruby exposes command-line arguments through ARGV.

# greet.rb
name = ARGV[0]
puts "Hello, #{name}!"

Run it:

ruby greet.rb Ada

Output:

Hello, Ada!

For a connection script, named options are usually clearer. Ruby's standard-library OptionParser can parse them:

require "optparse"

options = {}

OptionParser.new do |parser|
  parser.on("--source-host HOST", "Source IMAP host") do |host|
    options[:source_host] = host
  end

  parser.on("--source-port PORT", Integer, "Source IMAP port") do |port|
    options[:source_port] = port
  end
end.parse!

puts options.inspect

Run it:

ruby sync.rb --source-host mail.example.com --source-port 143

The Integer argument tells OptionParser to convert the port from text into an integer. Named options can appear in any order, which is safer than depending on ARGV[0], ARGV[1], and so on.

Step by Step Execution

Consider this script:

# connect.rb
host = ARGV[0]
port = Integer(ARGV[1])
ssl  = ARGV[2] == "true"

puts "Host: #{host}"
puts "Port: #{port}"
puts "SSL: #{ssl}"

Run it:

ruby connect.rb imap.gmail.com 993 true

Execution steps:

  1. Ruby starts connect.rb and creates ARGV:

    ["imap.gmail.com", "993", "true"]
    
  2. ARGV[0] is assigned to host, so host becomes "imap.gmail.com".

  3. ARGV[1] is "993", which is a string. Integer("993") converts it to the number 993.

  4. ARGV[2] == "true" compares the text exactly. It evaluates to true, so ssl becomes the Boolean value true.

  5. puts displays the parsed settings.

If the port is missing or not numeric, Integer raises an error. In a production script, validate input and print a helpful usage message instead of allowing an unclear failure.

Real World Use Cases

Command-line input makes scripts reusable in many situations:

  • Email migrations: Run one synchronization command per account from a CSV-driven PowerShell or Ruby script.
  • File processing: Pass an input filename, output directory, and processing mode.
  • Deployments: Provide a target environment such as --environment staging.
  • API utilities: Pass an endpoint, date range, and report format while keeping API keys in environment variables.
  • Scheduled jobs: Configure a task with options rather than maintaining separate copies of the same script.
  • Data imports: Select a database host, input file, and dry-run mode at runtime.
Take Quiz

Real Codebase Usage

In real Ruby projects, developers normally combine clear option parsing, validation, and secure secret handling.

Use named options for non-secret settings

ruby sync.rb --source-user alice --source-host mail.example.com --dest-user alice@gmail.com

Named options are self-documenting and remain understandable in logs or task definitions.

Use environment variables for passwords

In PowerShell:

$env:SOURCE_PASS = "source-password"
$env:DEST_PASS = "destination-password"
ruby sync.rb --source-user alice --source-host mail.example.com --dest-user alice@gmail.com

In Ruby:

source_pass = ENV.fetch("SOURCE_PASS")
dest_pass = ENV.fetch("DEST_PASS")

ENV.fetch fails immediately if the required value is absent, which is better than silently continuing with nil.

Validate before connecting

A common pattern is to check required values before doing network work:

required = %i[source_host source_user dest_host dest_user]
missing = required.reject { |key| options[key] }
abort "Missing required options: #{missing.join(', ')}" unless missing.empty?

Store account lists outside the code

For hundreds of accounts, put non-secret account metadata in a CSV, JSON, or database. Then loop through each record and invoke synchronization logic. Keep secrets in a protected credential store or retrieve them through an approved secret-management approach.

Common Mistakes

Treating all arguments as the correct type

Arguments are always strings initially.

port = ARGV[0]
# port is "993", not 993

Convert values that need numeric types:

port = Integer(ARGV[0])

Assuming strings become Boolean values

This code is incorrect:

ssl = ARGV[0]
if ssl
  puts "SSL enabled"
end

Even "false" is a non-empty string and is therefore truthy in Ruby. Parse it explicitly:

ssl = ARGV[0] == "true"

For more robust validation:

ssl_text = ARGV[0]
abort "SSL must be true or false" unless %w[true false].include?(ssl_text)
ssl = ssl_text == "true"

Using constants for per-run configuration

Constants such as SOURCE_HOST are appropriate for values that should not change during a program's lifetime. Runtime options are clearer as local variables or entries in an options hash.

source_host = options[:source_host]

Exposing passwords in commands

Avoid this where possible:

ruby sync.rb --source-pass my-secret-password

It may be saved in command history or visible to other users or tools. Prefer ENV.fetch("SOURCE_PASS") or another protected secret source.

Not checking missing arguments

This can fail later with confusing errors:

host = ARGV[0]
# host may be nil

Check required input early, or let OptionParser provide a usage message.

Using too many positional arguments

This is hard to maintain:

ruby sync.rb alice host 143 false password bob host2 993 true password2

Use named options, especially when a script has more than two or three inputs.

Comparisons

ApproachBest forStrengthsLimitations
ARGV positional argumentsTiny scripts with one or two valuesMinimal codeOrder-dependent and hard to read with many values
OptionParser named optionsCommand-line tools with several settingsClear names, help text, type conversionRequires a little more setup
Environment variables (ENV)Passwords, tokens, and deployment-specific settingsKeeps secrets out of the argument listMust be set before running the script
Configuration fileReusable groups of non-secret settingsConvenient for many accountsMust be protected and validated; do not casually store passwords in plain text

Positional versus named options

# Positional: the order must be remembered.
ruby sync.rb mail.example.com 143

# Named: each value identifies itself.
ruby sync.rb --source-host mail.example.com --source-port 143

ARGV versus ENV

host = ARGV[0]                 # Supplied in the command itself
password = ENV.fetch("PASS")  # Supplied through the environment

Use ARGV for ordinary user-facing input and ENV for sensitive or environment-specific values.

Take Quiz

Cheat Sheet

# All command-line arguments
ARGV

# First positional argument
name = ARGV[0]

# Convert a numeric argument
port = Integer(ARGV[1])

# Parse a true/false argument
ssl = ARGV[2] == "true"

# Read a required environment variable
password = ENV.fetch("SOURCE_PASS")

# Stop with an error message
abort "Missing --source-host"
require "optparse"

options = {}
OptionParser.new do |parser|
  parser.on("--host HOST") { |value| options[:host] = value }
  parser.on("--port PORT", Integer) { |value| options[:port] = value }
  parser.on("--ssl", "Use SSL") { options[:ssl] = true }
end.parse!

Key rules:

  • ARGV values start as strings.
  • "false" is truthy in Ruby; parse Boolean text explicitly.
  • Use Integer(value) for numeric validation and conversion.
  • Prefer named options when there are several inputs.
  • Do not normally put passwords directly in command-line arguments.
  • OptionParser#parse! reads options and removes them from ARGV.

FAQ

How do I access command-line arguments in Ruby?

Use the ARGV array. ARGV[0] is the first argument after the script name, ARGV[1] is the second, and so on.

Why is my Ruby command-line port a string?

The shell sends arguments as text. Convert a port with Integer(ARGV[0]) or use OptionParser with the Integer type.

How do I pass a Boolean value to a Ruby script?

Use a deliberate comparison such as value == "true". Do not use a non-empty string directly in an if, because both "true" and "false" are truthy in Ruby.

Should I pass a password as a command-line argument?

Usually no. It can appear in command history, logs, or process information. Use an environment variable, a protected configuration system, or a secret manager.

What is OptionParser in Ruby?

OptionParser is a Ruby standard-library tool for accepting named command-line options, generating help text, and converting option values to types such as integers.

Can I use command-line options on Windows with RubyInstaller?

Yes. Ruby's ARGV, ENV, and OptionParser work on Windows. Use Command Prompt or PowerShell syntax appropriate to the shell you are using.

What should I use for hundreds of accounts?

Keep the script configurable, and store account metadata in a CSV, JSON file, or database. Iterate over those records while retrieving passwords from a secure source.

Take Quiz

Mini Project

Description

Build a small Ruby command-line configuration checker for an IMAP synchronization job. It accepts source and destination connection settings as named options, reads passwords from environment variables, validates required values, and prints a safe summary without displaying secrets.

Goal

Create a reusable command that validates IMAP settings for any account without editing Ruby source code.

Requirements

Use OptionParser to accept source and destination host, user, and port options. Accept --source-ssl and --dest-ssl as flags. Read SOURCE_PASS and DEST_PASS from environment variables. Reject missing required options before printing the configuration. Do not print either password.

Take Quiz

Keep learning

Related questions

View more