Monday, August 25, 2008

Groovy's -e and friends: The Command Line for Java Developers

At the risk of turning this into a Groovy blog, here's an extended comment on a neat post by Jesse Wilson.

With its Java-friendly syntax and command-line options, Groovy opens up some serious possibilities on the command line.

Check out the doc for all the details and examples.

Here are some of the basics:

The -e option

Groovy's -e option accepts a one-liner as the input program. Many languages allow this but few offer such tight integration with Java.

For example, we can format a date. (Note that I'll use Unix-style line continuations here, but these are a single line.)

$ groovy -e " println \
> new java.text.SimpleDateFormat('yyyy.MM.dd G') \
> .format( new Date() ) "
$ 2008.08.25 AD
Note how easy it is to experiment with the format string. I work in an open "war-room", and often use little snippets like this to answer questions on the behaviour of various Java libraries.

Here we use java.util.Random. (Note: Groovy imports java.util.* by default.)

$ groovy -e " println new Random().nextInt(25) "
$ 18

The -n option

The -n option instructs Groovy to use standard input. The doc asks if there is a bug, but it seems to works fine for these examples.

In this mode, Groovy will provide the line and count variables like so (note the content of the file is shown first):

$ cat abc.txt

$ cat abc.txt | groovy -n -e " println count + ' : ' + line "
1 : a
2 : b
3 : c
When combined with Bash, this opens up a whole new world.

Java RegExs

It is difficult to duplicate Jesse's program with a single line. However, it is easy to use Java's regular expressions inline.

First, build an input file:

$ echo " CodeToJoy" > foo.txt

Here is the Groovy, in multi-line form for clarity:

// The =~ operator applies line against
// a regex within the /'s, and returns a Java matcher.
// The regex is a plain old Java regex.
// If new to Groovy, 'def' is like 'Object' (for now)

def m = ( line =~ /http:\/\/([\w.]+)\S*/ )

// Using Groovy truth: if m matched, then the matching
// groups can be accessed via an array.

if( m ) println m[0][1]

The one-liner looks like this (again Unix-style line continuations here):

$ cat foo.txt | groovy -n -e " \
> def m = ( line =~ /http:\/\/([\w.]+)\S*/ ) ; \
> if( m ) println m[0][1] "
The Upshot

Grails gets a lot of press, but Groovy offers a lot of utility, even on the modest command line. This is especially true when combined with Unix shells like Bash.

Sometimes, I want to use other tools but this damn language just won't go away as a useful option.

No comments: