Advanced Ag
I want to talk about one of the more powerful tools in my toolbox - Ag. As a developer I’ll bet you spend a fair amount of time writing code, but I’d argue you spend even more time reading code. Having a solid understanding of your language’s standard library, or a framework’s core abstractions will no doubt come in handy, but if you’re working on anything larger than a Hello World program chances are you spend a lot of time digging through code - lots of code. This is where a code searching tool like Ag proves indespensible. Yes, Ag can do your basic keyword searches, but so can your favorite editor. I want to share some of the more advanced options I find myself using day-to-day to shine a light on just how powerful of a tool it can be.
All examples will use Flipper as an example codebase we can search through. Feel free to git clone https://github.com/jnunemaker/flipper.git && cd flipper
to follow along!
Why Ag?
- fast…really fast (orders of magnitude faster than grep/ack)
- version control system awareness - ignores file patterns in your .gitignore
- ignores file patterns added to .ignore (eg .min.js)
Install
brew install ag
Basic Searching
ag [file-type] [options] PATTERN [PATH]
With one argument Ag recursively searches the current directory for the given pattern.
ag Gate
Pass it a second argument to recursively search a directory. This becomes especially useful when working in an opinionated framework like Rails where I know all of my controller code lives under app/controllers, specs under spec/controllers, etc.
ag Gate spec
Whole Word
Often we’re searching for a pattern that appears in many different contexts within our app. Usually this is a core domain concept like User, Property, or Gate. We only want to hit on cases where this pattern is a whole word - meaning not a subset of a larger word.
ag Gate
Note how Gate
is matched, but so is Flipper::GateNotFound
since it contains Gate
.
ag -w Gate
File Type
ag --ruby User
ag --js console
Restrict search to specific file-type. This is really useful if you have, for example, Ruby and JavaScript services that share the same name.
To see all supported file-types: ag --list-file-types
.
List
Ag returns the filename and line matching PATTERN. Sometimes we just want to list the filenames.
ag Gate -l
ag Gate -l | sort
- pro tip: who doesn’t prefer a sorted list?
File Pattern
Limit search to file names (including path) that contain a pattern:
ag User -G controllers
Usecase:
Your Rails and JavaScript admin panel code are both namespaced under an admin directory and you want to search both:
ag User -G /admin/
Ignore Directory
ag UserCreator --ignore-dir spec/
--ignore-dir
can be used to search everywhere, except a given directory. Multiple directories can be ignored by repeating the option.
ag User --ignore-dir spec/ --ignore-dir config/
.
Piping
Ag reads from Standard Input, allowing us to pipe results into the filter.
Usecase 1: searching rails routes
In rails we can get an overview of all defined routes by running the rake routes
task. With thousands of routes and not enough coffee left in my mug this would take way too long to search through by hand.
rake routes
rake routes | ag sign_in
Usecase 2: filtering logs
Have you ever tried to figure out which controllers actions are handling requests on page load? Rails logs every request a controller processes. With Ag we can easily filter for these messages:
tail -f log/development.log
tail -f log/development.log | ag "Processing by"
Usecase 3: killing processes
Every once in a while I’ll try to shut down an irb session by sending a SIGINT via ctrl-c, only to have the process fail to terminate. When a process wants to play these kind of games there’s only one option - SIGTERM baby!
Get the PID by listing running processes with ps -ax
Filter the results for any irb processes ps -ax | ag irb
kill 78154
Regex
ag [file-type] [options] PATTERN [PATH]
We’ve mostly seen basic words as the PATTERN parameter. It turns out PATTERN supports Perl-style regular expressions making Ag’s searching capablities limitless.
Usecase: very specific searches
Let’s search for every reference to the Feature
class in files ending in adapter.rb or store.rb.
ag -w -G "(adapter|store).rb$"
Context
man ag | ag -C case
Ag will display the line matching PATTERN, but sometimes we need some more context. For this we can pass the context (-C) flag to print the 2 lines above and below each match. Note the difference between the above command and the result of man ag | ag case
.
EOF
This really just scratches the surface of the powers of Ag. To learn more be sure to take a read through the man pages (man ag
) in your shell of choice.
Happy hacking Ag-ing!