Skip to content

Repository files navigation

Source Code GREP (SCGREP)

Build and test Go Reference License

Why?

grep-like commands on unix-like OSes are great. They come pre-installed. In fact, a search using grep is faster than the search on your IDE when there is no code index.

But, one key pain when using grep for searching in your source code or configuration files? A grep -r scans all files (including binary files 🫣) and not just source code files, making it slow. Sometimes, very slow.

What?

scgrep, which stands for 'source code grep', is a lightweight CLI tool that wraps your system's grep command and runs it only on source code files. Flags and pattern you pass to scgrep are passed as is to the underlying grep command, making it almost 100% compatible with grep. So, no need to learn a new syntax!

scgrep runs not one but multiple grep commands in parallel, making it significantly faster on large directories.

How to install?

  1. Install Go version at least 1.25
  2. Run command:
    go install github.com/m-manu/scgrep@latest
  3. Add following line in your .bashrc/.zshrc file:
    export PATH="$PATH:$HOME/go/bin"

Examples of usage

Simple usage

# Below is equivalent to searching for string "LinkedHashSet" in the current directory and its subdirectories
# It's equivalent to `grep -r LinkedHashSet` (but traverses only source code files)
scgrep "LinkedHashSet"

# Below is same as above but passes `--color` flag to the underlying `grep` (Colorized output) 
scgrep --color "LinkedHashSet"

# Below is same as above but passes `--color` and `-iw` flags to the underlying `grep` (Colorized output, case-insensitive, whole word only)
scgrep --color -iw "todo"

Specify directories to scan for

scgrep provides a specific flag --directories that lets you specify multiple directories

# Searches `./src/main` and `./src/test` for `LinkedHashSet`, with color. 
# Both roots are validated as readable directories before scanning starts.
scgrep --color "LinkedHashSet" --directories ./src/main ./src/test

Note: Order matters for --directories (everything after --directories is treated as a directory path)

Patterns that look like flags

scgrep -- -weird-pattern

A bare -- ends grep's own flag parsing. Useful when the pattern starts with a -.

Override the underlying grep

scgrep --grep-cmd fgrep "LinkedHashSet"
scgrep --grep-cmd=/usr/bin/grep -n "main"

If the chosen command is not on PATH (or the absolute path does not exist), scgrep exits with code 6 and does not run a search.

Git unavailable?

scgrep doesn't reimplement the logic to ignore files in .gitignore in a git repo. It relies on underlying git command instead. If git is not installed or is not in $PATH, scgrep uses its default source-code awareness behavior.

FAQs

Why not source-code-aware search tools like ack or ripgrep (rg) or something similar?

These tools reimplement the grep logic, in their own ways. In many cases, they're not compatible with grep.

scgrep acts as a thin wrapper and lets you use your own grep and just adds source-code awareness.

What is the exact logic of "source code awareness" this tool follows?

scgrep command traverses file tree with source code awareness in following ways:

  1. Scans for files with known source code and configuration file extensions (case-insensitive)
    • e.g..java, .go, .py, .yml etc. (see full list)
  2. Scans for files with certain names (case-sensitive)
    • e.g. postinst, Dockerfile etc. (see full list)
  3. Skips scanning certain directories (case-sensitive)
    • e.g. .git, .idea, .gradle etc. (see full list)
  4. Skips scanning certain directories with specific peer files (case-sensitive)
    • e.g. skip build subdirectory when build.gradle exists in the same directory etc. (see full list)

Additionally, when git is available and the search root is inside a Git working tree, scgrep respects the .gitignore file (via git ls-files).

How does scgrep handle recursive flags?

Flags such as -r, -R and --recursive get ignored. scgrep passes these flags as is to the underlying grep, which ignores these flags because underlying grep receives list of file names (not directories) as arguments.

e.g. Output of scgrep -r -i "TODO" would be same as scgrep -i "TODO"

Are there any exceptions to scgrep's compatibibility with grep?

Yes, just a couple:

  1. Options --directories, --grep-cmd, --version, -h/--help that scgrep consumes directly and does not pass to grep
  2. A -H it adds to grep when you have not already requested filenames (This is required to view the matching file names)

About

A blazing-fast, source-code-aware `grep` wrapper. Searches only real source files and skips build artifacts, binaries, vendor dirs etc. Respects `.gitignore` file.

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages