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!