ag in practice
Posted on Fri 03 June 2022 in Linux
Introduction
The silver searcher, or ag
for short, is a tool for searching text.
It relies on pthreads
, so it is generally faster than other tools, like ack
.
I've been using ag
instead of grep
these days for searching strings in a large codebase.
This post gives a few examples of using ag
in practice.
Using wildcards
Say you want to find the string "main.install.encoder"
. Such a string is a key for getting an environment variable.
Therefore, you may expect to find it in your codebase like in these examples:
# match these lines
getSytemVariable("main.install.encoder")
getSytemVariable(Constants.MAIN_INSTALL + ".encoder")
# not these lines
getSytemVariable("main.install.decoder")
getSytemVariable(Constants.MAIN_INSTALL + ".decoder")
In this case, you can define a placeholder between getSystemVariable
and encoder
as follows:
ag "getSystemVariable.*encoder"
This pattern allows us to search for a string that contains getSystemVariable
, followed by some characters (.*
), and then followed by encoder
.
It is similar to using grep
like this:
grep "getSystemVariable" | grep "encoder"
Example
$ ag "getSystemVariable.*encoder"
main.py
1:getSystemVariable("main.install.encoder")
2:getSystemVariable(Constants.MAIN_INSTALL + ".encoder")
$ grep -r "getSystemVariable" . | grep -r "encoder" .
./main.py:getSystemVariable("main.install.encoder")
./main.py:getSystemVariable(Constants.MAIN_INSTALL + ".encoder")
Now, suppose there is a file like this:
<getSystemVariable>
<value>encoder</value>
</getSystemVariable>
If you run ag "getSystemVariable.*encoder"
, then you will not get any matches. I think this is because getSystemVariable
and encoder
are located in different lines.
If the content is converted to a single line, then the pattern will match:
<functions><getSystemVariable><value>main.install.encoder</value></getSystemVariable></functions>
ag "getSystemVariable.*encoder"
config.xml
1:<functions><getSystemVariable><value>main.install.encoder</value></getSystemVariable></functions>
main.py
1:getSystemVariable("main.install.encoder")
2:getSystemVariable(Constants.MAIN_INSTALL + ".encoder")
There is a drawback, though: If there is a file that contains a large line, then ag
could match it and print it out.
Consider this example:
<functions><getSystemVariable> ... more content .... <value>main.install.encoder</value> ... more content ... </getSystemVariable></functions>
If you run ag "getSystemVariable.*encoder"
, it will find a match that can potentially occupy your whole terminal screen.
In addition, you are likely not interested in that match. Instead, you want to find getSystemVariable
, followed by some characters, and encoder
.
In this scenario, you can limit the amount of characters as follows:
ag "getSystemVariable.{0,30}encoder"
Example
ag "getSystemVariable.{0,30}encoder"
main.py
1:getSystemVariable("main.install.encoder")
2:getSystemVariable(Constants.MAIN_INSTALL + ".encoder")
Here, we specify that the maximum number of characters between getSystemVariable
and encoder
is 30
.
By doing this, we can prevent matching a large line and print it out.