Sag / Sack

“sag” / “sack” – a shortcut tool for ag / ack / grep:

(open sourced, on github: https://github.com/sampson-chen/sack)

Updated 2013-01-25: the_silver_searcher: Added support to use ag as the search tool via sag. (Clean-up and sgrep will have to wait a bit)

While learning and working with project codebases on the command line, I find myself constantly relying on grep to navigate my way around. I soon realized that I spent entirely too much time on:

  1. Typing out the file paths from the grep search results,
  2. Typing out the same flags for grep every time, and
  3. Moving between directories to initiate a search from the codebase root, and then having to move back to the directory (pressing tab a number of times) that I was originally working in:


(“arggghh!!“)

Mental context-switches are expensive. Often, after redirecting attention to type out the long file paths (at times making silly mistakes with cd, as above) and open the required files, you have already lost your train of thought. The time cost is now greater than just the 10-15 seconds from keying out a long file path.

This issue led me to thinking: “Gee, it sure would be nice to have a tool to handle these menial tasks automatically.” The search for such a tool on Google (and among fellow developers) yielded no results. So I decided to just write a tool for it: can’t possibly take that long, right?

I originally started with sgrep, as in “s(hortcut)grep”. However, upon discovering ack (http://betterthangrep.com/), the replacement for grep, I decided to write sack - “s(hortcut)ack” instead.

Here is how sack can save you valuable time and mental effort:

We’ll use a similar example to the one before, but using sack instead:

Notice that it uses preset flags (“-i“) for the current profile (“RB“) and performs the search under a set of pre-specified directories.

(If you prefer not to use any preset flags / search directories, there is a empty profile called “no_profile” for using sack exactly the same way you would with ack / grep.)

Now for the fun part! See the little tags that prefix the search results? Sack adds those to the search result of ack: instead of typing out a long file path to access the 59th result, simply do:

user@linux:~$ F 59

on the prompt and it will open the correct file with Vim (or Emacs, or another editor), and then even go directly to the line corresponding to the search result for you:

Note that whenever you perform a search in any terminal with sack, you can use the shortcuts in all other terminals (including new ones). So now you can use one terminal to keep the search results open for reference, and use other terminals to open the files of interest, via shortcuts.

Huzzah, productivity!

Using profiles is easy. For example, here’s switching profiles in sack:

There are a number of other things you can do with profiles, such as renaming a profile, setting preset flags / search directories for a profile, adding new profiles – these are documented on the github page for sack, and sack --help on the command line.

I shall leave the rest for you to explore. My hope is that this will make your life easier when navigating around codebases. If you have any suggestions on how you would improve this tool, please don’t hesitate to let me know! =)

7 thoughts on “Sag / Sack

  1. Instead of writing a special-purpose tool, you might have just used
    (1) cut-and-paste shortcuts and/or mouse gestures for copying the paths
    (2) grep -lr thumbnail . | xargs vim

    “grep -l” (grep dash lowercase L) lists the files that match a certain pattern, without showing the match itself. “xargs” is a command-line utility that takes a space- or newline-separated list of strings (in this case, filenames) and passes them as arguments to another process (in this case, your editor of choice).

    • hey AC:

      Thank you for you comments! This is exactly the type of feedback I’m looking for from developers who use grep and/or ack on a regular basis.

      My motivation for writing sack originally came from performing tasks such as reviewing all client code of certain API calls in a codebase, or refactoring to use strncpy instead of strcpy for security. Using (1) was fine, but I still found it tedious to do it repeatedly; I am under the impression that option (2) opens all the files that contain a match – which would work for certain scenarios (but there are situations where you might want to be more selective)

      Give sack a try =) I still use it because I find it saves me time on a daily basis, and more importantly it cuts out the need for me to mentally context-switch to think about file paths.

  2. Instead of:

    >3. Moving between directories to initiate a search from the codebase root, and then having to move back to the directory (pressing tab a number of times) that I was originally working in

    cd -

  3. I often find myself performing the same usage pattern – the difference is that I use `ag` (The Silver Searcher; `brew install the_silver_searcher` on OSX, or https://github.com/ggreer/the_silver_searcher) in lieu of ack.

    If I get some free time I’ll see if I can’t branch a “sag”. Would also like an option to just copy the file name – not the full path – to the clipboard (piping to pbcopy in OSX is what I do nowadays) because I’ll be honest: I love vim but when writing Java I really need to use an IDE. Eclipse’s ridiculously over-chromed search dialog sucks which is why I rely on ag.

    • Hey Charles, thanks for your feedback! I’ve heard many good things about `ag` recently and read about the its benchmarks against grep and ack; I’m quite swamped with school and interviews for the next little while, but I’m excited to try it out the next chance I get.

      Copying to clipboard / command substitution of file path is an idea I played around with before, but didn’t get around to. I’ll keep you updated if I think of a clean way to implement it. =)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>