File searching
find, fd, locate, grep, ripgrep.
find
Name + type
By name:
find /etc -name "*.conf"Case-insensitive:
find /home -iname "*.jpg"Directories only:
find /var -type d -name "log*"Files only:
find . -type f -name "*.txt"
Size
+ = greater than, - = less than. Suffix: c (bytes), k, M, G.
100 MB:
find / -type f -size +100M
Time
-mtime (days), -mmin (minutes). - = less than N ago, + = more than. Also -atime, -ctime.
Modified < 7 days:
find /home -type f -mtime -7Modified > 30 days:
find /var/log -type f -mtime +30Changed in last hour:
find . -type f -mmin -60
Other filters
Empty:
find /tmp -emptyExact perms:
find / -type f -perm 777SUID:
find / -type f -perm /u+sBy owner / group:
find /home -type f -user jofind /var -type f -group wheel
Combine
AND (default):
find . -type f -name "*.log" -size +10MOR:
find . -type f \( -name "*.jpg" -o -name "*.png" \)Negate:
find . -type f ! -name "*.tmp"
Depth
Max 2 levels:
find . -maxdepth 2 -name "*.conf"Direct child dirs in /etc:
find /etc -mindepth 1 -maxdepth 1 -type d
Exec
Per-file:
find . -type f -name "*.log" -exec rm {} \;With confirmation:
find . -type f -name "*.bak" -ok rm {} \;Batched (more efficient):
find . -type f -name "*.txt" -exec grep -l "TODO" {} +Built-in delete (fastest):
find /tmp -type f -name "*.tmp" -mtime +7 -delete
Tricks
Sort by mtime:
find . -type f -printf "%T@ %p\n" | sort -nBroken symlinks:
find . -xtype lExclude a dir:
find . -path ./node_modules -prune -o -type f -name "*.js" -printExclude multiple:
find . \( -path ./.git -o -path ./vendor \) -prune -o -type f -print
fd
Install fd. Recursive + smart-case + respects .gitignore + colorized by default.
Regex name search:
fd "\.conf$" /etcBy extension:
fd -e jpgfd -e txt -e mdInclude hidden / ignored:
fd -H ".bashrc"fd -I "node_modules"fd -HI "*.log"Type (
f/d/l/x/e):fd -t d "src"fd -t f "config"fd -t x# executablefd -t e# emptyMax depth:
fd -d 2 "*.md"Exclude dirs:
fd -E node_modules -E .git "\.js$"Absolute paths:
fd -a "\.conf$" /etcBase directory:
fd -e rs --base-directory /usr/src
Exec (-x per result, -X batch)
Placeholders: {} full, {.} no ext, {/} basename, {//} parent, {/.} basename no ext.
Per result:
fd -e log -x gzip {}Parallel convert:
fd -e png -x convert {} {.}.webpBatched:
fd -e txt -X wc -lMove with placeholders:
fd -e jpg -x mv {} {//}/thumbnails/{/}
Filter size / time
Size:
fd -S +1m -e logModified time:
fd --changed-within 1dfd --changed-before "2025-01-01"
locate / plocate
Install plocate.
Update DB (run as root or via timer):
sudo updatedbSearch:
locate bashrcCase-insensitive:
locate -i readmeCount matches:
locate -c "*.conf"Limit results:
locate -l 10 "*.log"Only existing files:
locate -e "*.conf"Regex:
locate -r "/etc/.*\.conf$"Regex + insensitive:
locate -ri "readme\.md$"DB stats:
locate -S
grep
Basic:
grep "error" /var/log/syslogRecursive:
grep -r "TODO" ./srcRecursive, skip binary:
grep -rI "password" /etcCase-insensitive:
grep -ri "error" /var/log/
Output control
Line numbers:
grep -rn "function" ./srcFilenames only:
grep -rl "import React" ./srcCount per file:
grep -rc "TODO" ./srcContext:
grep -B 3 "panic" log # 3 before grep -A 5 "error" log # 5 after grep -C 2 "fatal" log # 2 both
Regex flavors
Extended (
-E):grep -E "(error|warning|fatal)" logPerl (
-P):grep -P "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" access.log
Match modes
Invert:
grep -v "^#" /etc/fstabWhole word:
grep -w "error" logExact line:
grep -x "exact line" fileFixed string (no regex):
grep -F "user.name[0]" config
Multiple patterns
-erepeated:grep -e "error" -e "warning" logFrom file:
grep -f patterns.txt log
Include / exclude
Include:
grep -r --include="*.py" "import" ./srcExclude:
grep -r --exclude="*.min.js" "function" ./srcExclude dir:
grep -r --exclude-dir=".git" "TODO" .
Other
Null output for xargs:
grep -rZl "TODO" ./src | xargs -0 rmOnly matched portion:
grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" access.logQuiet (exit code):
if grep -q "error" log; then echo "found"; fi
ripgrep (rg)
Install ripgrep. Faster, sensible defaults, respects .gitignore.
Basic:
rg "TODO"In directory:
rg "error" /var/logFixed string:
rg -F "user.name[0]"
File types
One type:
rg -t py "import"Multiple:
rg -t js -t ts "fetch"List available types:
rg --type-listCustom type:
rg --type-add "web:*.{html,css,js}" -t web "color"
Case
Insensitive:
rg -i "error"Smart case (sensitive if uppercase used):
rg -S "Error"
Output
Context:
rg -C 3 "panic"rg -B 2 -A 5 "error"Files only:
rg -l "TODO"Files without match:
rg --files-without-match "TODO"Counts per file:
rg -c "error" /var/log
Hidden / ignored
Hidden:
rg --hidden "secret"Ignore
.gitignore:rg --no-ignore "debug"Everything (hidden + ignored):
rg -uu "password"
Globs
Include:
rg -g "*.py" "import"Exclude:
rg -g "!*.min.js" "function"Path glob:
rg -g "src/**/*.ts" "interface"
Advanced
Multiline:
rg -U "fn main.*\{[\s\S]*?\}"Replace preview:
rg "foo" -r "bar"Only matched portion:
rg -o "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"JSON output:
rg --json "TODO"Sort by path:
rg --sort path "error"Max depth:
rg --max-depth 2 "config"Max matches per file:
rg -m 5 "error"In compressed files:
rg -z "error" logs.gzNull separator for xargs:
rg -0 -l "TODO" | xargs -0 sed -i 's/TODO/DONE/g'Stats:
rg --stats "TODO"PCRE2 (lookahead/lookbehind):
rg -P "(?<=user=)\w+" access.log
Combine
Find then grep:
find . -name "*.conf" -exec grep -l "Listen" {} +fd + rg:
fd -e py | xargs rg "import os"Recently modified only:
fd -e log --changed-within 1h -x rg "error" {}locate + grep:
locate -r "\.conf$" | xargs grep -l "port"Large log files w/ errors:
find /var/log -name "*.log" -size +10M -exec grep -l "ERROR" {} +Duplicate filenames:
fd -t f | awk -F/ '{print $NF}' | sort | uniq -dOpen matches in editor:
rg -l "TODO" | xargs $EDITORLOC by extension:
fd -e py | xargs wc -l | sort -nInteractive search (fzf):
fd -t f | fzf --preview 'bat {}'rg --files | fzf --preview 'head -50 {}'