Ruby one-liner scripts Sep 17 2018

Ruby excels in its simplicity. It allows programmers to go from idea to implementation in a short time without much overhead. While many programmers have only heard of Ruby in relation to the web framework Rails, the scripting side of Ruby is very interesting and a rewarding use of the language. In this post, I will show you how to use Ruby to build one-liner scripts, and I will explain some useful flags when using Ruby scripts to process text.

Ruby one-liners

We call a script a one-liner when the Ruby interpreter is executed with a -e flag for a short Ruby program directly on the command line:

1
ruby -e 'puts Time.now' > current_time.log

This example shows the basic usage, but it is only helpful in illustrating how to execute a command sent as an argument.

One of the most common tasks we do in our scripts is text processing, that is, searching for patterns and manipulating data. Nowadays most modern operating systems represent everything as a file so it is useful to explore Ruby’s capabilities for file and text processing.

Useful interpreter flags

Ruby’s interpreter provides some interesting flags that help you create compact one-liners, here is a list with a description of what each flag does:

-n : tells the interpreter to run the command for each line in the file received as a parameter, each line can be reference by the global variable $_

-p : same as n but prints $_ (it represents the current line being processed) at the end of the execution

-C directory : the interpreter will switch to the specified directory and run on that scope

-F pattern : specifies the field separator, stored in the global variable $;

-U : sets the encoding to UTF8

-i(extension) : activates inline editing, this means that the interpreter will replace the line with everything the command sends to the system out.

-a : tells the interpreter to auto-split the line, by default using spaces as the separator ( can be overridden by the -F flag) and sets the array to the global $F variable.

Let’s see some examples that will show how to use the flags.

If we run the following command:

1
echo "Hello" | ruby -e 'puts "received: #{$_}"'

We would get only:

1
received:

We need to tell the interpreter to iterate through each line, in this example only one line (“Hello”), so we need to use the -n flag:

1
echo "Hello" | ruby -n -e 'puts "received: #{$_}"'

Now we would see on the screen:

1
received: Hello

Let's create a file that has the following content and let’s call it test.txt:

1
2
3
apple manzana
banana banano
cherry cereza

Now if we iterate through the lines and just print them we could use the following command:

1
cat test.txt | ruby -n -e 'puts $_'

And we should see each line printed on the screen. We used the puts method but we can use the flag -p to make the script more compact:

1
cat test.txt | ruby -p -e '$_'

Now let’s capitalize each line:

1
cat test.txt | ruby -p -e '$_ = $_.capitalize' 

When you run the code, you see that only the first letter of each line is being capitalized, we would like each word to be capitalized. We can split each line by spaces and capitalize all the words.

1
cat test.txt | ruby -n -a -e 'puts $F.map{|word| word.capitalize}.join(" ")'

Now we want to replace the content of the original file, not only display it on screen. We will keep a copy of the original file adding the extension .orig. We do this by executing the following command:

1
ruby -i.orig -n -a -e 'puts $F.map{|word| word.capitalize}.join(" ")' test.txt

Note that we now pass the name of the file as an argument. If we just passed stdout, as we were doing before through the pipe, we would get an error saying that we can’t do in-place edit on stdio.

If our file had the fields separated by commas, we could change the default separator using the flag -F

1
ruby -i.orig -F, -n -a -e 'puts $F.map{|word| word.capitalize}.join(" ")' test.txt

And if we wish to do a search and replace on many files we can combine find and xargs to make things easy:

1
find ./ -name "*.ledger" | xargs -n 1 ruby -pi.bak -e 'gsub(/BoA/,"Bank of America")'

I hope this gives you new ideas on how to build your own ruby one-liners. Try to use it on your day to day scripting and let me know if you have any questions or comments.


** If you want to check what else I'm currently doing, be sure to follow me on twitter @rderik or subscribe to the newsletter. If you want to send me a direct message, you can send it to derik@rderik.com.