Linux Basic — grep -E in Scripts
grep -E in Scripts
grep -E (or its alias egrep) interprets your pattern as ERE — the same dialect awk and Bash’s =~ use. For scripting it’s almost always what you want.
grep -E '^(ERROR|FATAL): ' app.log
Script-Friendly Flags
| Flag | Meaning | Why scripts love it |
|---|---|---|
-E |
extended regex | + ? ( ) \| without backslashes |
-q |
quiet — exit 0 if match, 1 if not | clean test in if / && |
-c |
count of matching lines | quick metrics |
-o |
print only the matched substring | extract data |
-n |
prefix with line number | reports |
-i |
case-insensitive | flexible matching |
-v |
invert match | filter out |
-r / -R |
recurse into directories | search trees |
-l |
list filenames only | feed into xargs |
-F |
fixed-string (no regex) | match literal *.log |
The Idiomatic Test
if grep -Eq '^https?://' <<< "$url"; then
echo "looks like a URL"
fi
-Eenables ERE-qsuppresses output (we only want the exit code)- here-string sends the variable as stdin without a subshell
This is the canonical “does this string match a pattern?” pattern in Bash.
Extract with -o
-o prints only the matched substring, one per line. Great for picking values out of structured text:
# pull every IPv4-ish token from a log
grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' access.log | sort -u
# pull email addresses
grep -Eoi '[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}' contacts.txt
Combine with head, wc -l, or sort | uniq -c to summarise.
Count Matches
err_count=$(grep -Ec '^ERROR' app.log)
echo "errors: $err_count"
-c counts lines, not occurrences — a line with two matches counts once. Use grep -Eo ... | wc -l for per-match counting.
Anchor Patterns to Avoid False Positives
# BAD — matches "10.20.30.40.567"
grep -E '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' input
# BETTER — word boundary on both sides
grep -Eo '\b([0-9]{1,3}\.){3}[0-9]{1,3}\b' input
\b is a GNU extension but widely available.
Pipelines
# only errors, then count by type
grep -E '^(ERROR|FATAL):' app.log \
| awk -F: '{print $1}' \
| sort | uniq -c | sort -rn
# files containing a pattern, opened for editing
grep -Erl '^TODO:' src/ | xargs -r $EDITOR
xargs -r is critical — it skips the call if input is empty (otherwise xargs runs the command with no args).
Pitfalls
| Pitfall | Fix |
|---|---|
Forgetting -E and using \(...\) weirdly |
Just use -E |
grep "..." inside an if prints noise |
Add -q |
grep -c on multi-match line gives wrong number |
Use grep -o ... \| wc -l |
Glob grep "*.log" instead of regex |
Use -F, or quote '\.log$' |
| Searching binaries by accident | grep -I skips binary files |
Next → Bash =~ Operator