2 shell search commands

Search text files using grep and skip Node 3rd party folders.

I always need to find either a file by filename or a file with certain string in it. I stopped using IDEs for development, so searching from the command line is my preferred way of finding things. Here are my two search commands from .search file in my .files repo.

Find file with given filename

Should be case insensitive, accept parts of the filename and find files by modified time. Under Unix I use the following command:

function f() {
    find . -iname "$1"
}
f foo*.js finds foo.js, foo-bar.js, etc
f f??.js finds foo.js

You can also easily find files newer than certain time period by adding -newerct 'period' argument

f foo*.js -newerct '1 month ago'
finds files created less than 1 month ago

If you need more power, for example to find files older than certain period, or by size, etc, take a look at the find command and find examples

Search inside files

To find files with given content, I use an alias to grep Prints filename, line number and the line itself with the found match.

alias fin="grep -in -ri \
  --exclude-dir=.git \
  --exclude-dir=node_modules \
  --exclude-dir=bower_components \
  --exclude-dir=dist"

To find all files with string "foobar" in folder "src"

fin "foobar" "src"

You can use regular expressions, for example fin "fo.bar" "src".

Open sublime at the found location

I love using Sublime, and when my find command finds a match, I can open sublime at the specific line. For example if I search for "sublime" in my blog posts, I get the following

$ fin sublime source/_posts
source/_posts/2-shell-search-commands.md:56:## Open sublime at the found location
source/_posts/2-shell-search-commands.md:58:I love using Sublime, and when my find command finds
source/_posts/2-shell-search-commands.md:59:For example if I search for "sublime" in
source/_posts/git-aliases.md:20:a lightweight text editor like *Notepad2* or *Sublime*
source/_posts/git-branches-with-descriptions.md:19:try another. For me Sublime does not work in this case, 
...

I can open the desired location using command subl source/_posts/git-aliases.md:20 and the Sublime text editor will understand the line number after the colon.

Open all found files in sublime

What if I want to open all found files in sublime? I can output just the filenames from grep using -l option.

$ fin -l sublime source/_posts
source/_posts/2-shell-search-commands.md
source/_posts/git-aliases.md
source/_posts/git-branches-with-descriptions.md
...

Notice that grep -l is smart enough to merge all filenames to a set. I can call sublime on each line using xargs command

$ fin -l sublime source/_posts | xargs subl

All text files that contain word "sublime" will be opened as tabs.

Update 1 - silver search

I have tried the_silver_searcher and it is super fast and uses .<ignore> file patterns to search only the real files!

Update 2 - reverse search

In Bash, when you have a lot of commands in the history, you can find a command by typing part of it. Hit Ctrl+r to start reverse search and start typing part of the command. Hit Ctrl+r to cycle through matching commands.

Also a tip: since # is a comment delimiter in Bash if you want to "label" a command type it as command #label then you can quickly find it using Ctrl+r #label.

Update 3 - Git history search for a file

Imagine you have a file in a Git history that has been deleted. To find all the commits that touched it:

1
git log --all --full-history -- <filename>

You can use wildcards in the filename. For example to find a file in a subfolder without knowing the exact extension

1
git log --all --full-history -- **/<filename.*>

Example: find deleted file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ md test-git-history
$ git init
Initialized empty Git repository in /private/tmp/test-git-history/.git/
$ g touch foo.txt
$ echo 'foo'>>foo.txt
$ g done "initial add foo"
[master (root-commit) f5e0f83] initial add foo
1 file changed, 1 insertion(+)
create mode 100644 foo.txt
$ g rm foo.txt
rm 'foo.txt'
$ g done "remove foo.txt"
[master 3ee3cf3] remove foo.txt
1 file changed, 1 deletion(-)
delete mode 100644 foo.txt
$ git log --all --full-history -- foo.txt
commit 3ee3cf32af5af74bce4d367e6f69161e9cd7f3ce
Author: Gleb Bahmutov <[email protected]>
Date: Tue Sep 12 10:58:15 2017 -0400

remove foo.txt

commit f5e0f8357288c97ae4bfcaea967c8cb1bd76ec8f
Author: Gleb Bahmutov <[email protected]>
Date: Tue Sep 12 10:58:06 2017 -0400

initial add foo