Ruby in your shell!
Ru brings Ruby's expressiveness, cleanliness, and readability to the command line.
It lets you avoid looking up pesky options in man pages and Googling how to write a transformation in bash that would take you approximately 1s to write in Ruby.
For example, to center a file's lines, use String#center:
ru 'map(:center, 80)' myfileUsing traditional tools, this isn't as easy or readable:
awk 'printf "%" int(40+length($0)/2) "s\n", $0' myfileFor another example, let's compare summing the lines of a list of integers using Ru vs. a traditional approach:
ru 'map(:to_i).sum' myfileawk '{s+=$1} END {print s}' myfileAny method from Ruby Core and Active Support can be used. Ru also provides new methods (and modifies #map) to make transformations easier. Here are some variations on the above example:
ru 'map(:to_i, 10).sum' myfile
ru 'map(:to_i).reduce(&:+)' myfile
ru 'each_line.to_i.to_a.sum' myfile
ru 'grep(/^\d+$/).map(:to_i).sum' myfile
ru 'map { |n| n.to_i }.reduce(&:+)' myfile
ru 'reduce(0) { |sum, n| sum + n.to_i }' myfile
ru 'each_line.match(/(\d+)/)[1].to_i.to_a.sum' myfile
ru 'map { |n| n.to_i }.reduce(0) { |sum, n| sum + n }' myfileSee Examples and Methods for more.
gem install ruYou can now use Ruby in your shell!
For example, to sum a list of integers:
$ printf "2\n3" | ru 'map(:to_i).sum'
5See Examples below, too!
Ru reads from stdin:
$ printf "2\n3" | ru 'map(:to_i).sum'
5
$ cat myfile | ru 'map(:to_i).sum'
5Or from file(s):
$ ru 'map(:to_i).sum' myfile
5
$ ru 'map(:to_i).sum' myfile myfile
10You can also run Ruby code without any input by prepending a ! :
$ ru '! 2 + 3'
5The code argument is run as if it has $stdin.each_line.map(&:chomp). prepended to it. The result is converted to a string and printed. So, if you run ru 'map(&:to_i).sum', you can think of it as running puts $stdin.each_line.map(&:chomp).map(&:to_i).sum.
In addition to the methods provided by Ruby Core and Active Support, Ru provides other methods for performing transformations, like each_line, files, and grep, and it improves map. See Methods for more.
Let's compare the readability and conciseness of Ru relative to existing tools:
ru 'map(:center, 80)' myfileawk 'printf "%" int(40+length($0)/2) "s\n", $0' myfileru 'map(:to_i).sum' myfileawk '{s+=$1} END {print s}' myfilepaste -s -d+ myfile | bcru '[4]' myfilesed '5q;d' myfileru '[1..-2]' myfilesed '1d;$d' myfileru 'map { |line| [line[/(\d+)( ".+"){2}$/, 1].to_i, line] }.sort.reverse.map(:join, " ")' access.logawk --re-interval '{ match($0, /(([^[:space:]]+|\[[^\]]+\]|"[^"]+")[[:space:]]+){7}/, m); print m[2], $0 }' access.log | sort -nk 1In addition to the methods provided by Ruby Core and Active Support, Ru provides other methods for performing transformations.
Provides a shorthand for calling methods on each iteration of the input. Best explained by example:
ru 'each_line.strip.center(80)' myfileIf you'd like to transform it back into a list, call to_a:
ru 'each_line.strip.to_a.map(:center, 80)' myfileConverts the lines to Ru::File objects (see Ru::File below).
$ printf "foo.txt" | ru 'files.map(:updated_at).map(:strftime, ""%Y-%m-%d")'
2014-11-08Formats a list of Ru::Files. You'll typically call this after calling files to transform them into strings:
$ ru 'files.format'
644 tom staff 3 2014-10-26 09:06 bar.txt
644 tom staff 11 2014-11-04 08:29 foo.txtThe default format, 'l', is shown above. It prints [omode, owner, group, size, date, name].
Selects lines which match the given regex.
$ printf "john\npaul\ngeorge" | ru 'grep(/o[h|r]/)'
john
georgeThis is the same as Array#map, but it adds a new syntax that allows you to easily pass arguments to a method. For example:
$ printf "john\npaul" | ru 'map(:[], 0)'
j
p
$ printf "john\npaul" | ru 'map(:center, 8, ".")'
..john..
..paul..Note that the examples above can also be performed with each_line:
$ printf "john\npaul" | ru 'each_line[0]'
$ printf "john\npaul" | ru 'each_line.center(8, ".")'The files method returns an enumerable of Ru::Files, which are similar to Ruby Core's File. Each one has the following methods:
basenamecreated_at(alias for ctime)ctimeextnameformat(see theformatmethod above)ftypegidgroupmodemtimename(alias for basename)omodeownersizeto_s(alias for name)uidupdated_at(alias for mtime)world_readable?
Ru lets you save commands by name, so that you can easily use them later.
Save a command for future use:
$ ru save sum 'map(:to_i).sum'
Saved command: sum is 'map(:to_i).sum'Run a saved command:
$ printf "2\n3" | ru run sum
5
$ ru run sum myfile
5List all of your saved commands:
$ ru list
Saved commands:
sum map(:to_i).sumPrint a help page.
Print the installed version of Ru.
Ru is tested against Active Support 3 and 4. If you'd like to submit a PR, please be sure to use Appraisal to test your changes in both contexts:
appraisal rspecRu is released under the MIT License. Please see the MIT-LICENSE file for details.