Monday, July 4, 2011

Adding Line Numbers to File with Groovy's -p and -e Options

A commonly used example to demonstrate Groovy's groovy launcher -e and -p options is adding line numbers to a specified text file. Not only does this demonstrate the -e and -p options well, but its a useful little tool because there are often times when we want to quickly see a line number in a file for reference. In this post, I look at a couple variations of this common example.

The Groovy CLI section of the Groovy User Guide offers several examples of using command-line Groovy with the options -i, -e, and -p. Some of these examples include adding line numbers to a text file. For example, the page currently includes this example:

groovy -pi .bak -e "count + ': ' + line"

The -i option tells Groovy to modify the supplied file in place and the .bak specified after that tells Groovy to create a backup file with the .bak extension. However, for my first version of this, I'm going to use a slightly modified version without modifying in place and thus without specifying a backup file extension. Here is the revised version:

groovy -p -e "count + ': ' + line"

To demonstrate the use of the above, I will use a simple Java class called TimeZoneIDs.java, whose code listing is shown next.

TimeZoneIDs.java
package dustin.examples;

import java.util.Arrays;
import java.util.TimeZone;
import static java.lang.System.out;

public class TimeZoneIds
{
   public static void main(final String[] arguments)
   {
      out.println(Arrays.toString(TimeZone.getAvailableIDs()));
   }
}

To use the simple command-line Groovy command to add line numbers to the above listed Java source code, I simply type (in DOS) or cat (in Linux) the file and pipe it to the Groovy command shown above. This is demonstrated in the next screen snapshot.


All one would need to do at this point is add a redirection (>) to this output and redirect it to any desired file.

The "count" in the above example was implicitly available to the Groovy launcher and represented the count of the line currently being processed. In other words, by virtue of using the -p option to process and print the contents on a per line basis, the "count" variable was implicitly available as a BigInteger. Likewise, the "line" variable is also available implicitly and is a handle to the String containing the current line itself that is being processed.

The one downside to the above is that the number of digits in the line numbers changes and this makes the spacing a little off after line 9. This can be easily remedied with a minor addition to the above command.

groovy -p -e "count.toString().padLeft(2) + ': ' + line"

The next screen snapshot demonstrates that running this version more nicely aligns the text of the file as long as the number of lines does not go into three digits.


A disadvantage of the last example is that the spacing can still be off if there are more lines than anticipated and specified to the String.padLeft call. One way to deal with this is to pick a very high number of characters to pad to. Another approach would be to first determine the number of lines of code and then set the padding appropriately. One can also choose to use the overloaded version of the GDK's String.padLeft to pass a different padding character than space (such as "0").

One approach that can be used to find the number of lines in the file via Groovy and the -e option is shown in the next example (against the TimeZoneIds.java class in this particular case).

groovy -e "println new File('TimeZoneIds.java').readLines().size()"

When the above is run on my example, it returns the integer 13. That tells me that 2 places should be sufficient for the number of digits in the largest line number. This is also another Groovy one-liner!

Another thing to note is that you should typically specify -p or -n before specifying -e because -e expects the Groovy script in quotes as a parameter that goes with it. Alternatively, you can combine them and use -pe as demonstrated in the next screen snapshot.


Adding line numbers to a text file is another example of a Groovy one-liner that is small enough that it doesn't even need a script file and can be used with Groovy's -e and -p options. Another good reference for additional details on these options is Groovy's -e and friends: The Command Line for Java Developers.

No comments: