Search for files & file names using Silver Searcher
Asked Answered
S

6

32

Using Silver Searcher, how can I search for:

  1. (non-binary) files with a word or pattern AND
  2. all filenames, with a word or pattern including filenames of binary files.

Other preferences: would like to have a case-insensitive search and search through dotfiles.


Tried to alias using this without much luck:

alias search="ag -g $1 --smart-case --hidden && ag --smart-case --hidden $1"

Silverpoint answered 10/9, 2013 at 7:49 Comment(1)
If you're using that alias in bash, you should note that bash aliases don't take parameters.Marlenmarlena
R
60

According to the man page of ag

   -G --file-search-regex PATTERN
          Only search files whose names match PATTERN.

You can use the -G option to perform searches on files matching a pattern.

So, to answer your question:

root@apache107:~/rpm-4.12.0.1# ag -G cpio.c size
rpm2cpio.c
21:    off_t payload_size;
73:    /* Retrieve payload size and compression type. */
76:     payload_size = headerGetNumber(h, RPMTAG_LONGARCHIVESIZE);

the above command searches for the word size in all files that matches the pattern cpio.c

Reference:
man page of ag version 0.28.0

Note 1:

If you are looking for a string in certain file types, say all C sources code, there is an undocumented feature in ag to help you quickly restrict searches to certain file types.

The commands below both look for foo in all php files:

find . -name \*.php -exec grep foo {}
ag --php foo

While find + grep looks for all .php files, the --php switch in the ag command actually looks for the following file extensions:

.php  .phpt  .php3  .php4  .php5  .phtml

You can use --cpp for C++ source files, --hh for .h files, --js for JavaScript etc etc. A full list can be found here

Note 2:

Keep in mind that when using language specific flags such as --php alongside the --file-search-regex option, then the --file-search-regex appears to be ignored at least per this example below

$ mkdir ag-test
$ cd ag-test
$ echo hello > blah.php
$ echo hello > mmkay.php
$ echo hello > special_something.txt
$ echo hello > special_also.php
$ echo nothing > nope.php
$ echo nothing > nada.php
$ echo nothing > special.php

# Only --php
$ ag --php  -l hello .|cat
special_also.php
mmkay.php
blah.php

# Only --file-search-regex
$ ag  --file-search-regex special  -l hello .|cat
special_also.php
special_something.txt

# Both
$ ag --php --file-search-regex special  -l hello .|cat
special_also.php
mmkay.php
blah.php
Rinse answered 20/1, 2015 at 22:22 Comment(9)
Nice, not sure how I missed -g and -G back when I submitted my original answer. The OP's wording is kind of confusing but I think what he wants is to run a single command that searches all filenames as well as nonbinary file contents. Seems like ag -g [search] && ag -l [search] would work.Midyear
I suppose this is a better answer and I should mark this answer? Any thoughts?Silverpoint
@JikkuJose I added a new answer, which I believe solves your original question completelyMidyear
@JikkuJose I think the community agrees that this is a better answer to your question.Rinse
-g also deserves a place in your answer.Bizet
Seems like correct answer, but does not work for me. ag does not seem to have a way to get version, so cannot know if it due to older version on brew/Mac.Christian
@Christian try ag --versionRinse
if you have extra time and are not in a rush, you can as well do it with our good old slower brother: grep -Hirn --include "*haystack*" needle *Fullfledged
chatgpt got me close, but humans still win for the moment... +1Midrash
C
10

Try this:

find . | ag "/.*SEARCHTERM[^/]*$"

The command find . will list all files.

We pipe the output of that to the command ag "/.*SEARCHTERM[^/]*$", which matches SEARCHTERM if it's in the filename, and not just the full path.

Charwoman answered 18/12, 2013 at 1:4 Comment(1)
Had almost solved a variant using a simpler solution: ag -g . | ag 'search_term'; Yes, your pattern can be used to filter to the filename and not the path.Silverpoint
M
5

Try adding this to your aliases file. Tested with zsh but should work with bash. The problem you encountered in your example is that bash aliases can't take parameters, so you have to first define a function to use the parameter(s) and then assign your alias to that function.

searchfunction() {
  echo $(ag -g $1 --hidden)
  echo $(ag --hidden -l $1)
}

alias search=searchfunction

You could modify this example to suit your purpose in a few ways, eg

  • add/remove the -l flag depending on whether or not you want text results to show the text match or just the filename
  • add headers to separate text results and filename results
  • deduplicate results to account for files that match both on filename and text, etc.

[Edit: removed unnecessary --smart-case flag per Pablo Bianchi's comment]

Midyear answered 28/7, 2015 at 19:24 Comment(4)
Any way to tweak this to work with 'sack/sag' (github.com/sampson-chen/sack)? That would require combining the two ag queries into one so the search cache from first command that sack relies on wouldn't get blown away.Bucket
You can omit a parameter: -S --smart-case Match case-sensitively if there are any uppercase letters in PATTERN, case-insensitively otherwise. Enabled by default.Pundit
@PabloBianchi thanks. I had a (very) old version of ag, whose man page did not have the "enabled by default" note, but upon testing, it seems even old versions of ag did indeed use this flag by default. Updated my answer.Midyear
how to get this to output each result on a new line?Window
M
4

Found this question looking for the same answer myself. It doesn't seem like ag has any native capability to search file and directory names. The answers above from Zach Fogg and Jikku Jose both work, but piping find . can be very slow if you're working in a big directory.

I'd recommend using find directly, which is much faster than piping it through ag:

Linux (GNU version of find)

find -name [pattern]

OSX (BSD version of find)

find [pattern]

If you need more help with find, this guide from Digital Ocean is pretty good. I include this because the man pages for find are outrageously dense if you just want to figure out basic usage.

Midyear answered 15/10, 2014 at 21:23 Comment(3)
Thanks for confirmingSilverpoint
@JikkuJose would you remove this as an accepted answer? Looking back, it is clearly incorrect in light of the -g and -G flags available with agMidyear
@Midyear fyi, -g is an output optionDwanadwane
D
4

To add to the previous answers, you can use an "Or" Regular Expression to search within files matching different file extensions.

For example to just search a string in C++ header files [.hpp] and Makefiles [.mk] ) :

ag -G '.*\.(hpp|mk)' my_string_to_search

Declaratory answered 4/1, 2019 at 17:39 Comment(0)
A
1

After being unsatisfied with mdfind, find, locate, and other attempts, the following worked for me. It uses tree to get the initial list of files, ag to filter out directories, and then awk to print the matching files themselves.

I wound up using tree because it was more (and more easily) configurable than the other solutions I tried and is fast.

This is a fish function:

function ff --description 'Find files matching given string'
  tree . --prune --matchdirs -P "*$argv*" -I "webpack" -i -f --ignore-case -p |
    ag '\[[^d].*' |
    awk '{print $2}'
end

This gives output similar to the following:

~/temp/hello_world $ ff controller
./app/controllers/application_controller.rb
./config/initializers/application_controller_renderer.rb
~/temp/hello_world $
Academician answered 18/4, 2019 at 20:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.