»  Home · About · Posts by Topic

Ack is awesome

Sep 9, 2015 ·  The grep replacement ack is an invaluable part of my toolbox. I'll explain why and show some examples and some tipps.

This is the second time I highlight Andy Lester’s work on my blog. Back in 2013 I reviewed his book Land the Tech Job You Love which is my favorite tech career guide. Now I want to highlight his open-source tool ack which is “a tool like grep, optimized for programmers”. I use it every day and I have observed many times that people who don’t use it are slower at tasks that require locating files.

The ack website has a page “Top 10 reasons to use ack for source code” which I don’t want to repeat here. All of these reasons are true in my experience. I’ll just go through my personal main reasons to use ack.

It’s easy to search only the right files

Grep can search in explicitly listed files, or in all files in a directory tree. Ack can search in files of certain types under a directory tree.

I used to do find . -name "*.xml" -exec grep -H foo '{}' \;. I guess grep foo $(find ...) would have been a bit easier, I learned this later.

Now I just do ack --xml foo.

And it’s even better than the find version because it doesn’t search in .git and similar directories. This unclutters the output and makes it run faster. Perl’s optimized regex engine is pretty fast anyways.

For every file type --foo you can also request --nofoo to exclude it.

For certain types such as --shell ack will even check the shebang line of files that don’t have an extension.

What’s more, while there are many predefined file types, you can define your own, and they are not limited to a single extension.

You can also use this functionality to simple list all files of a type, for example to pipe them into another command. Simply add -f: ack -f --java --xml.

If you’d like to only consider files in subdirectories matching a certain pattern, ack has you covered as well. ack -g 'src/main' searches only in src/main folders.

These are just the main ways to tell ack which files you’re interested in. Combined, they save me a lot of time when locating files.

Java example

I mainly work in Java these days. My project root has a bunch of Maven modules in it, each in its own subdirectory. Inside each of those is a src/main, a src/test, and a target folder for build artefacts.

First, I don’t want to grep through the build artefacts ever. So I added --ignore-dir=target to my .ackrc. I also want to ignore IntelliJ’s internal project files, ending in .iml, which I ignore with --ignore-file=match:\.iml$.

Second, I tend to search a limited number of sets of files. Usually it’s either all files, or only Java files, or only XML files (Spring configuration). And sometimes I want to search either of those only in main code, or only in test code. I addressed this with a number of bash aliases that allow me to do all that in two or three keystrokes. (Yes, IntelliJ can do this as well, but I have other issues with it, and for many tasks the command line is superior.)

alias aj='ack --java'
alias am='ack -v -g '\''src/test'\'' | ack -x'
alias ajm='ack --java -v -g '\''src/test'\'' | ack -x'

The first one searches only Java files, the second one ignores src/test, and the third one combines those two. The aliases for XML and src/test are equivalent. I don’t use -g src/main for non-test code, but -v -g src/test which means “everything but src/test`. That way it also searches top-level files that are neither in main nor in test.

So, for example, axm FooFactory gives me all occurrences of FooFactory in XML and related files, in src/main of any Maven module.

We do need a small clutch here because ack can only either select files by path (-g), or search in files, but not both together. So we invoke it twice, once to select the files and once to search in them.

It’s fast and ergonomic

The ack website already lists this: ack is fast. But I’d like to emphasize that it’s fast not just in terms of runtime, but in interaction time. Instead of typing “grep -R” you type “ack”, many times a day. And with its ways of narrowing down the search as shown above, it obsoletes a whole bunch of piped shell expressions involving find and friends. I simply get to hit return sooner, saving time and mental effort.

Another point that doesn’t immediately seem related to speed is ack’s formatting of its output. When piped to another process, it’s mostly like grep’s. But when ack writes to the console, it formats for readability, intelligently using line breaks, colors, and highlighting. That makes it faster for me to scan the results of my search.

(Almost) great documentation

ack’s documentation is great, which allows everyone to get the most out of it. The “almost” is because it’s a bit scattered. There’s ack --help which lists the main options, useful as a quick reference. Then there’s the man page, also available via ack --man (useful on Windows). That distinction makes sense, but there’s a third place, the full documentation on the ack website. That’s something to be aware of when looking for info. It helps, though, that Stackoverflow has a large number of ack questions, many answered by Andy himself.

It’s mostly like grep

ack mostly uses the same flags than grep, and it behaves like grep. So all the flags you’re used to, like -i and -v, are there. I never had an issue switching between the two.

Conclusion

ack is one of those tools that may not sound all that impressive at first. After all, it’s a glorified grep. But, in my experience, with ack the sum is greater than its parts. The different improvements over grep work together and accumulate to make a significant difference. I think and type less than with grep and have more brainpower available for my actual task.