This is a work-in-progress draft version.
Recursive options
This chapter will cover the feature most attractive for users — the default recursive behavior and options to customize it. For beginners to recursive search using rg
, the --files
option to get list of files being searched can be useful. The --debug
and --trace
options could be used for further analysis, especially to know why a file is ignored. The --files
option is also handy if you want to use features of rg
in pruning filenames for further processing instead of glob match, find
command, etc.
Test directory
First, create a directory with multiple sub-directories, hidden files, etc.
$ cp /usr/share/dict/words words.txt
$ # 'context_matching' directory has 'context.txt' shown in Options chapter
$ # create directory for this section and cd into it
$ mkdir recursive_matching && cd $_
$ # create some files
$ printf 'hide\nobscure\nconceal\ncover\nblot\nshield' > patterns.txt
$ grep -Ff patterns.txt ../words.txt > .hidden
$ grep -E '([as]([b-g]|po)[r-t]){2}' ../words.txt > nested_group.txt
$ echo 'how are you?' > normal.txt
$ echo 'how dare you!' > 'filename with spaces.txt'
$ # create sub-directory, two scripts and another hidden file
$ mkdir scripts
$ echo 'yrneaolrknzcyr 86960' > scripts/.key
$ echo "tr 'a-z0-9' 'n-za-m5-90-4' < .key" > scripts/decode.sh
$ printf "import math\n\nprint(math.pi)\n" > scripts/pi.py
$ # create link to a directory
$ ln -s ../context_matching/
$ tree -al
.
├── context_matching -> ../context_matching/
│ └── context.txt
├── filename with spaces.txt
├── .hidden
├── nested_group.txt
├── normal.txt
├── patterns.txt
└── scripts
├── decode.sh
├── .key
└── pi.py
2 directories, 9 files
Default recursive behavior
$ # assumes 'recursive_matching' as CWD
$ rg --files
patterns.txt
scripts/pi.py
scripts/decode.sh
nested_group.txt
normal.txt
filename with spaces.txt
As seen from the example above, some of the files seem missing. That is because rg
performs recursive search with certain pre-set conditions:
- ignore files and directories that match rules specified by ignore files like
.gitignore
- ignore hidden files and directories
- ignore binary files (files containing ASCII NUL character) — but displays the match if found before encountering NUL character along with a warning
- ignore symbolic links
Effect of ignore files
Here's an example to show .gitignore
in action. The presence of .git
directory (either in current directory or in parent directories) would mark .gitignore
to be used for ignoring. Recently, --no-require-git
flag was added to avoid the need for empty .git
directory. For illustration purposes, empty .git
would be created here instead of using an actual git
project. In addition to .gitignore
, the rg
command also uses filenames like .ignore
and .rgignore
for determining files to ignore. For complete details and various ignore options, refer to manual as well as ripgrep: user guide.
See stackoverflow: .gitignore pattern format to learn about the various rules.
$ mkdir .git
$ echo 'patterns.txt' > .gitignore
$ rg -wl 'obscure|are'
normal.txt
$ # --no-ignore option will disable pruning based on ignore files
$ rg --no-ignore -wl 'obscure|are'
patterns.txt
normal.txt
Overriding default recursive behavior
Use the --hidden
option to search hidden files and directories as well.
$ # create normal file in a hidden directory
$ cp patterns.txt .git/pat.txt
$ # no output, and patterns.txt isn't matched because of .gitignore
$ rg -l 'obscure|ne'
$ rg --hidden -l 'obscure|ne'
scripts/.key
.git/pat.txt
.hidden
As a shortcut, you can use
-u
to indicate--no-ignore
-uu
to indicate--no-ignore --hidden
-uuu
to indicate--no-ignore --hidden --binary
Use -L
option to follow symbolic links.
$ rg 'red'
$ rg -Ll 'red'
context_matching/context.txt
Search based on filename extension
The -t
option provides a handy way to search files based on their extension. Use rg --type-list
to see all available types and their glob patterns. Use -T
to invert the selection.
$ rg --type-list | rg 'markdown'
markdown: *.markdown, *.md, *.mdown, *.mkdn
md: *.markdown, *.md, *.mdown, *.mkdn
$ # use rg --type-list | rg '^sh:' to see glob pattern for 'sh'
$ rg -t=py -t=sh --files
scripts/pi.py
scripts/decode.sh
$ # note that .gitignore is active
$ rg -t=txt --files
nested_group.txt
normal.txt
filename with spaces.txt
$ rg -T=txt --files
scripts/pi.py
scripts/decode.sh
Search based on glob pattern
Use -g
option to search only files matching the given glob pattern. Prefix !
to exclude the matches. If /
is not used, the glob will be matched against basename of all the files found recursively.
$ rg -g='*.{sh,py}' --files
scripts/pi.py
scripts/decode.sh
$ rg -g='*gr*' --files
nested_group.txt
$ # exclude filenames ending with py
$ rg -g='!*.py' --files
scripts/decode.sh
nested_group.txt
normal.txt
filename with spaces.txt
$ # exclude scripts directory
$ rg -g='!scripts' --files
nested_group.txt
normal.txt
filename with spaces.txt
You can use **
while constructing the glob pattern as a placeholder for zero or more levels of directories. See git documentation: gitignore pattern format for more details.
$ # create files/directories
$ mkdir double_star && cd $_
$ mkdir -p one/two/{x,y,z}/four
$ touch one/1.txt one/two/y/why.txt one/two/x/ex.txt one/two/y/four/4.txt
$ # all files
$ rg --files
one/1.txt
one/two/x/ex.txt
one/two/y/four/4.txt
one/two/y/why.txt
$ # file paths starting with 'one/two/'
$ rg -g='one/two/**' --files
one/two/x/ex.txt
one/two/y/four/4.txt
one/two/y/why.txt
$ # file paths having the directory 'y' anywhere in the path
$ rg -g='**/y/**' --files
one/two/y/four/4.txt
one/two/y/why.txt
$ # clean up temporary directory
$ cd .. && rm -r double_star
There are many more options to customize the search experience (for ex: defining your own type using
--type-add
option,--max-depth
to control depth of traversal, etc). See ripgrep user guide: configuration for examples and details on how to maintain them in a file.