Utility Ruby

Ruby and the System
Environment: ENV.class => Object # not Hash, but has some of the same methods ENV['OS'] ENV.has_key?('OS') Arguments: ARGV.class => Array ARGV[0] # first argument $0     # name of script System commands: begin x = `something` rescue Errno::ENOENT $stderr.puts("no such command") rescue $stderr.puts("unknown error") end Common taks: if system("command") then puts("command was executed successfully") end Dir.chdir "/path/to/some/dir" Common file tasks - fileutils: require 'fileutils' include FileUtils mkdir_p "/path/to/some/dir"

Renaming Files
Output script for renaming all files: require 'find' Find.find '.' do |f| if f =~ /regex/ then puts "mv '#{f}' '#{f.gsub(/regex/, "replacement")}'" end end Use like this: ruby createRenameScript.rb|tee /tmp/rename.sh|less If all is OK in the script, run it: . /tmp/rename.sh

Zero Padding
require 'find' largestNumberLength = 0 Find.find '.' do |f| if f =~ /.*?(\d+)\..*/ then numberLength = f.sub(/.*?(\d+)\..*/,'\1').length largestNumberLength = numberLength if numberLength > largestNumberLength end end Find.find '.' do |f| if f =~ /.*?(\d+)\..*/ then numberLength = f.sub(/.*?(\d+)\..*/,'\1').length if numberLength < largestNumberLength then zeroPadding = '0' * (largestNumberLength-numberLength) puts "move \"#{f}\" \"#{f.gsub(/(\d+)\./, "#{zeroPadding}\\1.")}\"" end end end
 * 1) find largest number length in file names
 * 1) rename files to include zero padding, e.g. file1.jpg => file001.jpg

Change Content
Simple example: require 'find' Find.find '.' do |f| if f =~ /.*\.txt$/ then puts "Modifying file: #{f}" infile = File.new(f, "r") lines = infile.readlines ; infile.close

(0..lines.length).each do |linenumber| line = lines[linenumber] if line =~ /first line/ then lines.insert(linenumber+1, "following after first line") end line.gsub!(/something/, "something else") end

# outfile = File.new(f, "w") # lines.each do |line| outfile.puts(line) end end end Change content of all files (careful with this): require 'find' require 'ftools' require 'fileutils' files_to_change = /.*/ regex = /(some|a lot of)\s+text/ replacement = '\1 more text' Dir.chdir(ARGV[0]) dir_name = File.basename(ARGV[0]) new_dir_name = dir_name + ".changed" dir_with_changed_files = "../" + new_dir_name created_dir_with_changed_files = false Find.find '.' do |file_name| if File.stat(file_name).file? and file_name =~ files_to_change then new_file_name = dir_with_changed_files + "/" + file_name # read all lines from file infile = File.new(file_name, "r") lines = infile.readlines ; infile.close # check if any lines should be changed change = false lines.each do |line| if line =~ regex then change = true ; break end end if change then if not created_dir_with_changed_files then if not File.exist?(dir_with_changed_files) then puts "creating #{new_dir_name}" FileUtils::mkdir(dir_with_changed_files) created_dir_with_changed_files = true else if File.stat(dir_with_changed_files).directory? then puts "reusing old #{new_dir_name}" created_dir_with_changed_files = true else puts "#{new_dir_name} exists but is not a directory." exit end end end # write modified lines to newfile puts "creating #{new_dir_name}/#{File.basename(file_name)}" outfile = File.new(new_file_name, "w") lines.each do |line| outfile.puts line.gsub(regex, replacement) end end end end if created_dir_with_changed_files then puts "view changes using\n diff -r #{ARGV[0]} #{ARGV[0]}.changed" puts "apply changes using\n cp -r #{ARGV[0]}.changed/* #{ARGV[0]}" end

Execute a Single Command
$ ruby -e "puts 2**16" 65536

Regex Search
require 'find' Find.find '..' do |f| puts "#{f}" if f =~ /regex/ then end or the really short one: find|ruby -ne'puts$_ if~/search/i' <- case-insensitive search

Filter
A bit like sed. Places  around the code

$ ruby -pe '$_.upcase!' ruby 1.8 RUBY 1.8 $ ruby -pe 'gsub(/[1-9]/,"x")' ruby 1.8 ruby x.x $ ruby -pe 'gsub(/[1-9]/,"x").upcase!' ruby 1.8 RUBY X.X

Mass-renaming:

ls|ruby -ne 'if ~/regex/ then puts "mv "+$_.strip+" "+$_.downcase end' |tee /tmp/rename.sh                \____/             \____________________________/           \____________/ |                            |                                 |        only look at matching files         output this               source this afterwards if ok

filter files in-place (like )

$ ruby -pi -e "gsub(/search/, 'replace')" *.txt $ ruby -pi.bak -e "gsub(/search/, 'replace')" *.txt  # with backup

Complex Example
example:

$ ruby -pe '$_=~/^#.*/?$_:$_=gsub(/[1-9]*:.*$/,"").split(".").collect{|x|x.capitalize}.join(" ")' stdin:                stdout: svend.hansen4: hej    svend hansen ...
 * 1) kommentar            # kommentar