warning warning warning 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.

info 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

info 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.