Shell Tricks: instant wildcard directory search

[Tweet]

Here’s a handy trick I use at the command line to quickly find filenames matching simple wildcard patterns in nested folders. It’s called lsgrep because that’s essentially what it does: grep a list of filenames and return matches.

Dependencies

This function uses The Silver Searcher (ag), which can be installed via Homebrew (brew install the_silver_searcher). It could easily be modified to work with ack or other grep replacement (or grep itself, with the right options).

Installation

Copy the function below into your ~/.bash_profile (or wherever you source functions from at login). Source the file to test it out (e.g. source ~/.bash_profile).

By default it recurses 3 levels deep into folders. You can modify this in the last line by changing the number after the --depth flag.

# Convert simplified wildcard pattern to regex and grep a file listing using
# Silver Searcher (`brew install the_silver_searcher`)
lsgrep ()
{
    NEEDLE="$(echo $@|sed -E 's/\.([a-z0-9]+)$/\\.\1/'|sed -E 's/\?/./'| sed -E 's/[ *]/.*?/g')";
    ag --depth 3 -S -g "$NEEDLE" 2> /dev/null
}

Wildcards

You’ll note that when it creates the $NEEDLE search term, it substitutes basic “*” and “?” wildcards for actual regular expressions. It also escapes “.” to search for a literal period. Spaces are converted to “.*” searches, meaning any number of characters can exist between the arguments. Thus:

$ lsgrep d?rty
source/_posts/2015-09-22-quick-and-dirty-json-validation-in-cocoa.md

$ lsgrep d rty # (or lsgrep d*rty)
node_modules/coffeelint/3rd_party_rules.md
post_backup/2010-11-01-a-little-rock-and-roll-inconsequential-martyr.md
source/_manually_copied/share/InconsequentialMartyr.mp3
source/_manually_copied/share/InconsequentialMartyr.ogg
source/_posts/2010-11-01-a-little-rock-and-roll-inconsequential-martyr.md
source/_posts/2015-03-05-marked-2-dot-4-11-party-like-its-9-dollars-dot-99.md
source/_posts/2015-09-22-quick-and-dirty-json-validation-in-cocoa.md
source/_posts/2016-11-03-great-games-just-in-time-for-the-holidays-sketchparty-tv-and-truth-truth-lie.md

In the first example you can see that the “?” wildcard only allowed one random character between “d” and “rty”, so the file containing “dirty” was returned. In the second example the search was converted to “d.*rty”, so any file with containing a “d” and then an “rty” at any point after is matched.

Limit By Filetype

The literal period substitution allows you to add an extension at the end of the query to limit the filetype.

$ lsgrep d*rty .md
node_modules/coffeelint/3rd_party_rules.md
post_backup/2010-11-01-a-little-rock-and-roll-inconsequential-martyr.md
source/_posts/2010-11-01-a-little-rock-and-roll-inconsequential-martyr.md
source/_posts/2015-03-05-marked-2-dot-4-11-party-like-its-9-dollars-dot-99.md
source/_posts/2015-09-22-quick-and-dirty-json-validation-in-cocoa.md
source/_posts/2016-11-03-great-games-just-in-time-for-the-holidays-sketchparty-tv-and-truth-truth-lie.md

It’s a great shortcut to find files you know the name of, and in iTerm you can then just Command-Click a result to open it in the appropriate editor. You can also use it in another command like cat $(lsgrep d?rty). I hope you find it as useful as I do!

Ryan Irelan has produced a series of shell trick videos based on BrettTerpstra.com posts. Readers can get 10% off using the coupon code TERPSTRA.