pdfq
Fast, parallel PDF search with a command line compatible with pdfgrep.
pdfq is a from-scratch rewrite in Rust. It extracts text page by page with
pdf-extract, matches with the regex crate (or fancy-regex for -P),
and searches pages on all cores with rayon. Output format, flags, and exit
codes follow pdfgrep so it can be used as a drop-in replacement.
Features
- pdfgrep-compatible flags:
-i,-n,-c,-o,-l,-L,-q,-F,-P,-A/-B/-C,-m,-r,-R,--color,--page-range, and more - Parallel page and file processing (rayon)
- Modern regex engines: Rust
regexby default,fancy-regexfor-P - Optional on-disk cache of extracted page text (
--cache) - GNU-grep-style exit codes:
0match,1no match,2error - Colored output honoring
GREP_COLORS(mt/ms/mc,fn,ln,se)
Build
The binary is target/release/pdfq.
Usage
Examples:
Run pdfq --help for the full option list.
Exit codes
| Code | Meaning |
|---|---|
| 0 | at least one match |
| 1 | no match |
| 2 | error (bad usage, unreadable file, ...) |
With -q, a match wins over errors: exit 0 as soon as anything matches.
Errors while walking directories recursively (-r) are reported on stderr
but do not change the exit code, matching pdfgrep.
Output format
[filename<sep>][pagenum<sep>]text
sepis:on match lines and-on context lines-nprints the page number (pdfgrep has no line numbers, PDFs are pages)-Zreplaces the filename separator with NUL- context groups are separated by
--, but only when lines were actually skipped
Differences from pdfgrep
- Text extraction uses
pdf-extract(pure Rust) instead of poppler, so layout reconstruction can differ slightly on complex PDFs .in a pattern does not match newline (Rust regex semantics; POSIX.does). Multi-line anchors:^matches only the start of the page text,$only the end- Recursive walk output is sorted by name for reproducible results; pdfgrep prints raw readdir order
--helpis generated by clap and lists every option, not pdfgrep's short "commonly used" list- No
--unacaccent folding (option is rejected with a clear error)
Testing
Unit and integration tests (includes a regression suite for the
encrypted-PDF password check vs --cache):
Differential tests against a reference pdfgrep binary (compares stdout, stderr, and exit codes; program name normalized):
PDFGREP=/path/to/pdfgrep
If PDFGREP is not set, the script uses pdfgrep from PATH and exits 2
when it is missing.
License
MIT