Ruby for Scripting and Automation
Ruby is an excellent choice for scripting and automation. Its clean syntax, powerful standard library, and excellent OS integration make it perfect for automating repetitive tasks, processing files, and building command-line tools. This tutorial covers the fundamentals of using Ruby for automation scripts.
Why Use Ruby for Scripting?
Ruby was designed for programmer happiness, and that shows in scripting tasks. Here’s why Ruby works well for automation:
- Readable syntax — Ruby reads almost like English, making scripts easy to understand and maintain
- Rich standard library — Everything from file handling to HTTP requests is built-in
- Cross-platform — Ruby runs on Linux, macOS, and Windows with the same code
- Great ecosystem — Tools like Rake, Thor, and Bundler make complex scripts manageable
Running Your First Script
Create a file called hello.rb with this content:
#!/usr/bin/env ruby
# A simple Ruby script
puts "Hello, Automation World!"
Run it with:
ruby hello.rb
The #!/usr/bin/env ruby shebang line lets you run the script directly (./hello.rb) on Unix systems.
Working with Files
One of the most common automation tasks is processing files. Ruby makes this straightforward.
Reading Files
# Read entire file into memory
content = File.read('data.txt')
puts content
# Read file line by line (memory efficient for large files)
File.foreach('data.txt') do |line|
puts line unless line.strip.empty?
end
Writing Files
# Write to a new file (overwrites existing content)
File.write('output.txt', 'Hello, World!')
# Append to existing file
File.open('log.txt', 'a') do |file|
file.puts "#{Time.now} - Script completed"
end
Processing CSV Files
Ruby’s CSV library makes data processing simple:
require 'csv'
CSV.foreach('data.csv', headers: true) do |row|
name = row['name']
email = row['email']
puts "#{name}: #{email}"
end
Running System Commands
Ruby can execute shell commands and capture their output.
Running Commands
# Run a command and get output
output = `ls -la`
puts output
# Or use the system method for more control
system('ls', '-la')
# Capture exit status
if $?.success?
puts "Command succeeded"
else
puts "Command failed with code: #{$?.exitcode}"
end
Using the open3 Library
For more control over command execution:
require 'open3'
stdout, stderr, status = Open3.capture3('ls', '-la')
if status.success?
puts stdout
else
puts "Error: #{stderr}"
end
Command-Line Arguments
Most automation scripts need to accept arguments:
# Access command-line arguments
filename = ARGV[0]
puts "Processing: #{filename}"
# Handle multiple arguments
ARGV.each_with_index do |arg, index|
puts "Argument #{index + 1}: #{arg}"
end
# Use options with optparse for complex CLI tools
require 'optparse'
options = { verbose: false, count: 1 }
OptionParser.new do |parser|
parser.on('-v', '--verbose', 'Increase verbosity') do
options[:verbose] = true
end
parser.on('-c N', '--count=N', Integer, 'Repeat N times') do |n|
options[:count] = n
end
end.parse!
puts "Running #{options[:count]} times" if options[:verbose]
Automating Repetitive Tasks
Here’s a practical example: processing all files in a directory:
#!/usr/bin/env ruby
require 'fileutils'
# Process all .txt files in current directory
Dir.glob('*.txt').each do |filename|
# Skip if file was modified today
next if File.mtime(filename) > Time.now - 86400
# Read and transform content
content = File.read(filename)
transformed = content.upcase
# Write to new file
new_filename = filename.sub('.txt', '_uppercase.txt')
File.write(new_filename, transformed)
puts "Processed: #{filename} -> #{new_filename}"
end
Working with JSON and YAML
Modern automation often involves configuration files:
require 'json'
require 'yaml'
# Read JSON
config = JSON.parse(File.read('config.json'))
puts config['database']['host']
# Read YAML
settings = YAML.load_file('settings.yaml')
puts settings['debug']
# Write JSON
File.write('output.json', JSON.pretty_generate(data))
Best Practices for Automation Scripts
- Use
require_relativefor loading local libraries - Add error handling with begin/rescue blocks
- Use Ruby’s logging library for script output
- Make scripts idempotent — running twice should be safe
- Add shebang lines for direct execution
- Handle signals (SIGINT, SIGTERM) for graceful shutdown
# Graceful shutdown handling
trap('SIGINT') do
puts "\nReceived interrupt. Finishing current task..."
exit 0
end
When to Use Ruby for Automation
Ruby excels at:
- File and directory processing
- Text manipulation and parsing
- Building CLI tools
- Quick prototyping of automation ideas
- System administration tasks
For heavy-duty data processing, consider combining Ruby with command-line tools like awk, sed, and sort via Ruby’s system integration.
Summary
Ruby provides a powerful yet readable way to automate tasks. Its file handling, system command integration, and rich standard library make it ideal for DevOps scripting. Start with simple scripts and gradually add complexity as needed. ENDADD
Environment Variables and Configuration
Automation scripts often need to read environment variables and handle configuration:
require 'json'
# Read environment variables
api_key = ENV['API_KEY']
database_url = ENV['DATABASE_URL'] || 'localhost:5432'
# Set default values
debug_mode = ENV.fetch('DEBUG', 'false') == 'true'
# Load configuration from JSON file
config = JSON.parse(File.read('config.json')) if File.exist?('config.json')
# Use environment variables in your script
puts "Running in #{ENV.fetch('RAILS_ENV', 'development')} mode" if debug_mode
Scheduling and Cron Integration
Ruby scripts work great with cron for scheduled automation:
#!/usr/bin/env ruby
# backup.rb - Example backup script for cron
require 'fileutils'
require 'time'
# Configuration
BACKUP_DIR = ENV['BACKUP_DIR'] || '/tmp/backups'
SOURCE_DIR = ARGV[0] || '/var/www'
timestamp = Time.now.strftime('%Y%m%d_%H%M%S')
backup_name = "backup_#{timestamp}.tar.gz"
backup_path = File.join(BACKUP_DIR, backup_name)
# Create backup directory if needed
FileUtils.mkdir_p(BACKUP_DIR)
# Create backup (using system tar command)
system('tar', '-czf', backup_path, '-C', SOURCE_DIR, '.')
if $?.success?
puts "Backup created: #{backup_path}"
# Clean old backups (keep last 7)
Dir.glob(File.join(BACKUP_DIR, 'backup_*.tar.gz'))
.sort[0...-7]
.each { |f| File.delete(f) }
else
puts "Backup failed!"
exit 1
end
To run this daily at 2 AM, add to your crontab:
0 2 * * * /usr/bin/ruby /path/to/backup.rb /data/to/backup
Error Handling in Scripts
Robust scripts handle errors gracefully:
begin
# Try to process the file
content = File.read(input_file)
processed = process_content(content)
File.write(output_file, processed)
rescue Errno::ENOENT => e
puts "Error: File not found - #{e.message}"
exit 1
rescue Errno::EACCES => e
puts "Error: Permission denied - #{e.message}"
exit 2
rescue StandardError => e
puts "Error: #{e.message}"
puts e.backtrace if ENV['DEBUG']
exit 3
ensure
puts "Script finished at #{Time.now}"
end
This pattern ensures your script provides useful error messages and exits with appropriate codes.