Skip to main content

Recursive Search

Historically, grep only read individual files. To search an entire directory tree, administrators had to use find to generate a list of files, and pipe them to xargs grep.

Modern GNU grep has recursive capabilities built-in, allowing it to crawl directories autonomously.

The Recursive Flags (-r vs -R)

To search a directory, pass the directory path as the final argument instead of a file, and use either -r or -R.

  • -r (Recursive, Default): Read all files under each directory recursively. It does NOT follow symbolic links (unless the symlink is passed explicitly on the command line).
  • -R (Dereference Recursive): Read all files recursively, and DO follow all symbolic links.
# Recursively search the entire /var/log directory
grep -r "auth_failure" /var/log/

# Search the current directory
grep -r "TODO" .
The Symlink Trap (-R)

Using -R is highly dangerous if you do not understand your filesystem. If a directory contains a symlink pointing back to /, grep -R will enter an infinite loop and eventually crash or hang the server.

Always default to -r. Only use -R if you explicitly know you need to traverse linked directories and are confident no recursive loops exist.

Recursive Output Defaults

When you use -r or -R, grep automatically enables the -H flag (print filenames). Because you are searching a directory tree, the output will prefix every match with its relative or absolute path (depending on how you defined the target directory).

# Output of grep -r "listen" /etc/nginx/
/etc/nginx/nginx.conf: listen 80;
/etc/nginx/conf.d/default.conf: listen 443 ssl;

The Pipe Alternative (find | xargs grep)

While grep -r is convenient, it is not always the most efficient choice, especially when searching massive directories. grep has basic include/exclude flags, but it lacks the granular metadata filtering of find.

If you only want to search .log files modified in the last 7 days, grep -r cannot do this alone. You must revert to the classic POSIX pipeline:

# 100% precise directory search
find /var/log -type f -name "*.log" -mtime -7 -print0 | xargs -0 grep "ERROR"

(Note: We use -print0 and -0 to safely handle filenames with spaces, as discussed in the find documentation).