Linux Basic — Regular Expressions Practice

3 minute read

Practice Exercises — Regular Expressions

Work through these using only grep, sed, awk, and Bash =~. Use -E (or ERE-native tools) throughout.


Warm-up — grep -E

  1. Find errors. From app.log, print every line starting with ERROR or FATAL.
  2. Quiet test. Write an if that uses grep -Eq to detect whether app.log contains any panic.
  3. Extract IPs. Print every IPv4-looking token from access.log, deduplicated and sorted.
  4. Email extraction. Pull every email address from a free-form text file. Case-insensitive.
  5. Count by category. Count how many lines start with INFO, WARN, ERROR and print as a 3-line summary.

Bash =~ Operator

  1. Validate a port number. Read a port from read -p; accept only digits, then check the range 1–65535.
  2. Parse a tag. Given tag="release-v2.4.1-rc3", extract major, minor, patch into named variables using BASH_REMATCH.
  3. Detect file type by name. Given a filename, branch into image, archive, script, or other using one [[ $f =~ ... ]] per branch.
  4. The quoting trap. Show that [[ "$x" =~ "^[0-9]+$" ]] matches only the literal string; then fix it.
  5. Email validator. Write a is_email() function returning 0/1 using a single [[ =~ ]] with a reasonable pattern.

POSIX Character Classes

  1. Identifier check. Use [[:alpha:]_][[:alnum:]_]* to validate identifiers (let grep -Eq or Bash =~ decide).
  2. Hex colour. Validate a string is # followed by exactly 6 hex digits ([[:xdigit:]]).
  3. Trim whitespace. Use sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//' on a file with mixed leading/trailing spaces.
  4. Locale impact. With LC_ALL=en_US.UTF-8, show that grep -Eo '[[:alpha:]]+' <<< "café" returns café; then with LC_ALL=C show it stops at caf.

sed

  1. Swap key=value. Convert name=Alice into Alice=name using a single sed -E with capture groups.
  2. Path rewrite. Replace /old/path with /new/path in a config — pick a non-/ delimiter.
  3. Delete blanks and comments. From an ini file, delete blank lines and lines beginning with ; or #.
  4. Section-scoped edit. In app.ini, change host=... to host=db.prod only inside the [database] section.
  5. Portable in-place. Implement a portable sed_inplace() function that works on both GNU and BSD sed using mktemp + mv.

awk

  1. Filter by field. From /etc/passwd, list usernames whose shell ends in bash.
  2. Sum a column. Given a CSV with name,amount rows, sum amount and print at END.
  3. Group-by count. From access.log, count requests per HTTP status code (assume status is field 9). Sort descending.
  4. Replace inside one field. In a tab-separated file, lowercase only column 3 and reprint the whole row.
  5. Dedupe adjacent. Remove consecutive duplicate lines without using uniq.
  6. CSV with embedded commas. Mention which assumption breaks plain -F, parsing, and pick the right tool (csvkit, mlr) for real CSV.

Stretch

  1. Build a small linter. Scan a directory of .sh files; print every line that uses unquoted $var (heuristic: grep -En '[^"]\$[A-Za-z_]'). Accept that this is a heuristic.
  2. Mask secrets in a log. Replace anything that looks like an API key ([A-Za-z0-9]{32,}) with ***REDACTED*** using sed -E.
  3. Two-pass awk. First pass: collect set of valid IDs from valid.txt. Second pass: print only events.csv rows whose ID is in the set. Use awk 'NR==FNR{...; next} {...}' valid.txt events.csv.
  4. Date range filter. From a log with YYYY-MM-DD at the start of each line, print only lines between two dates using awk and string comparison.
  5. Generate mv commands. Use ls | sed -E 's/(.*)\.txt$/mv & \1.md/' to rename .txt to .md — pipe through sh once you’ve verified.

Verification Checklist

  • Every pattern with ( ) + ? | uses -E (or awk / Bash =~)
  • [[:digit:]] etc. are inside two sets of brackets
  • All sed substitutions you’d run on real files are tested without -i first
  • All awk field accesses use the right -F separator
  • No regex is unanchored when validating input

Next chapter → Interactive Scripts

Updated: