Programmers often talk about how easy it is to interact with the shell from Ruby, using the %x[] or backtick syntax to fire off work.

These conveniences are great for most situations, but they start to fall down when presented with unusual inputs or strange pipeline gymnastics.

Spaces in Filenames

For example, a script to echo out the contents of a file might look like this.

#!/usr/bin/ruby
puts `cat #{ARGV[0]}`

This seems okay at first glance, if a little nonidiomatic. Upon closer inspection, however, we can see how it would fail when presented with a file whose name includes a space.

The simplest solution to this problem is to use a command-execution method that allows us to pass explicit arguments.

#!/usr/bin/ruby
puts exec("cat", ARGV[0])

By not conflating the command to be executed and its arguments, this code avoids the issue we saw with unusual filenames. Unfortunately, it has lost the ability to effectively harness the power of the Unix pipeline.

Supporting Pipes

Let’s reformulate that first example and add a pipe to the mix.

#!/usr/bin/ruby
puts `cat #{ARGV[0]} | sort`

This code works fine as long as the file we’re working with has no spaces in its filename. As of Ruby 1.9, it’s much simpler to deal with this scenario in a robust way. We can use Open3::pipeline_r to explicitly chain together several processes.

#!/usr/bin/ruby
require 'open3'
Open3.pipeline_r(["cat", ARGV[0]], ["sort"]) do |output|
  puts output.read
end

Open3

The Open3 module has a number of different methods to help you chain together different commands along the Unix pipeline, depending on your explicit needs. In this example I used pipeline_r to demonstrate the common scenario of passing the output of the sequence of shell commands to a Ruby method. Give Open3 a perusal and see if it can help you make your tools more versatile.

One Comment

  1. rkumar

    Thanks a lot. Spaces in filenames really mess with scripts too. I’ve been facing this alot in this script/utility I just wrote.

    I’ve just released it (under active development) … if you use the command-line a lot pls try it out and give me feedback.
    https://github.com/rkumar/zfm

Leave a Comment

Enclose code in <code lang="ruby"></code> if you care.
Preview your comment using the button below.