Some extractions need lookarounds, and in big codebases a tool that respects .gitignore is dramatically faster.
GNU grep's -P switches to Perl-compatible regular expressions (PCRE2). That adds:
- shorthand classes
\d,\w,\s, and\bword boundaries; - lazy quantifiers like
.*?; - lookarounds:
(?<=user=)\w+matches the name afteruser=without including the prefix; \K, which drops everything matched so far from the reported match:grep -oP 'id=\K\d+'prints just the number.
-P is a GNU feature and may be missing in minimal builds; BSD and macOS grep don't support it. In portable scripts, prefer -E plus sed or awk for extraction.
For searching source trees, two other tools are often better than grep -r:
git grepsearches only tracked files of a Git repository, very quickly, and can search other revisions:git grep TODO v1.0.- ripgrep (
rg) recurses by default, skips files ignored by.gitignore, hidden files and binaries, uses all CPU cores and has a regex engine with guaranteed linear-time matching. Its flags mirror grep's (-i,-w,-l,-C) and-t pyfilters by file type.
Keep plain grep for pipelines and for scripts that must run everywhere; use rg or git grep interactively in large repositories.
Example
printf 'user=ana id=17\nuser=bo id=204\n' > log.txt
grep -oP 'id=\K\d+' log.txt # 17 / 204
grep -oP '(?<=user=)\w+' log.txt # ana / bo
grep -oP 'user=.*?(?= )' log.txt # user=ana / user=bo (lazy + lookahead)
# portable equivalent without -P
grep -oE 'id=[0-9]+' log.txt | cut -d= -f2 # 17 / 204
# in a Git repository:
# git grep -n 'TODO' tracked files only
# rg -t py 'def main' ripgrep: respects .gitignore, parallelRemember
- grep -P adds \d, lazy quantifiers, lookarounds and \K
- -P is GNU-only: use -E with cut or sed in portable scripts
- git grep and ripgrep are faster for code search and skip ignored files
Watch out for
- Shipping a script that uses grep -P to macOS users, where it fails with an invalid option error.