Portrait of Michael Limberger

Michael Limberger

Need me? Email mike@limberger.ca

Regex

Practice Exercises

Type it until it sticks

Each exercise builds on the previous. Create a fresh practice directory first.

Show me.

mkdir ~/regex-workshop
cd ~/regex-workshop

Exercise 1 · files to chew on

Create these files for the rest of the night.

Show me. A log.

echo "2024-01-15 10:30:22 INFO Server started on port 8080" > server.log
echo "2024-01-15 10:31:05 WARNING High memory usage: 85%" >> server.log
echo "2024-01-15 10:32:17 ERROR Connection refused to database" >> server.log
echo "2024-01-15 10:33:44 INFO User 'admin' logged in" >> server.log
echo "2024-01-15 10:35:02 ERROR File not found: /tmp/cache.dat" >> server.log

Messy filenames:

touch "IMG 2024 01 15 photo.jpg"
touch "IMG 2024 01 16 sunset.jpg"
touch "IMG 2024 02 20 vacation.jpg"
touch "Document (1).txt"
touch "Document (2).txt"
touch "final_FINAL_v2.docx"

A tiny CSV:

echo "name,email,score" > scores.csv
echo "Alice,alice@example.com,95" >> scores.csv
echo "Bob,bob@test.org,87" >> scores.csv
echo "Carol,carol@demo.net,92" >> scores.csv

Exercise 2 · ack in the log

Find all ERROR lines:

ack "ERROR" server.log

Timestamps starting with 10:3:

ack "10:3\d" server.log

WARNING or ERROR:

ack "WARNING|ERROR" server.log

Challenge: find lines that mention a port number.

Exercise 3 · case

echo "The Quick Brown Fox" > animals.txt
echo "the quick brown fox" >> animals.txt
echo "THE QUICK BROWN FOX" >> animals.txt
ack -i "quick" animals.txt

Challenge: find all variations of "fox" as a whole word only.

Exercise 4 · extract

ack -o "\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}" server.log
ack -o "port \d+" server.log

Challenge: extract all usernames. Hint: look for quoted strings.

Exercise 5 · rename, dry-run first

rename -n 's/ /_/g' IMG*
rename 's/ /_/g' IMG*
rename -n 's/\s*\(\d+\)//' Document*
rename 's/\s*\(\d+\)//' Document*

Challenge: clean up "final_FINAL_v2.docx" to just "final.docx".

Exercise 6 · capture groups

Current: IMG_2024_01_15_photo.jpg. Target: 2024-01-15_photo.jpg.

rename -n 's/IMG_(\d{4})_(\d{2})_(\d{2})_(.+)/$1-$2-$3_$4/' IMG*
rename 's/IMG_(\d{4})_(\d{2})_(\d{2})_(.+)/$1-$2-$3_$4/' IMG*

Challenge: pad the day with a leading zero if needed. Hint: already done with \d{2}, but think about how you would handle IMG_2024_1_5_photo.jpg.

Exercise 7 · Perl, basic

perl -pe 's/ERROR/CRITICAL/' server.log
perl -pe 's/error/CRITICAL/gi' server.log
perl -ne 'print if /ERROR/' server.log

Challenge: print lines that do NOT contain INFO.

Exercise 8 · CSV

perl -F',' -ane 'print "$F[0]\n"' scores.csv
perl -F',' -ane 'print "$F[0]\n" if $. > 1' scores.csv
perl -F',' -ane 'print "$F[0],$F[2]" if $. > 1' scores.csv

Challenge: calculate the average score.

Exercise 9 · pull numbers out

perl -ne 'print "$1\n" if /([a-z0-9.]+@[a-z0-9.]+)/' scores.csv
perl -ne 'print "$1\n" if /(\d+)%/' server.log

Challenge: extract all numbers from server.log.

Exercise 10 · a small pipeline

A realistic scenario. AI output files to process.

mkdir ai_output
echo "PASS: Clean image" > ai_output/img001_result.txt
echo "REJECT: Nudity detected" > ai_output/img002_result.txt
echo "PASS: Clean image" > ai_output/img003_result.txt
echo "REJECT: Violence detected" > ai_output/img004_result.txt
echo "PASS: Clean image" > ai_output/img005_result.txt

Show me.

ack "REJECT" ai_output/
ack -l "REJECT" ai_output/
ack -c "PASS" ai_output/
ack -c "REJECT" ai_output/
ack -o "REJECT: .*" ai_output/
perl -ne 'print "$1\n" if /REJECT: (.+)/' ai_output/*.txt

Challenge: create a summary report showing counts by rejection type.

Bonus · a tiny script

Show me. process_results.sh

#!/bin/bash
# process_results.sh

echo "=== AI Results Summary ==="
echo ""

PASSES=$(ack -c "PASS" ai_output/ | perl -ne '$s += (split/:/)[1]; END{print $s}')
REJECTS=$(ack -c "REJECT" ai_output/ | perl -ne '$s += (split/:/)[1]; END{print $s}')

echo "Total PASS:   $PASSES"
echo "Total REJECT: $REJECTS"
echo ""
echo "=== Rejection Reasons ==="
perl -ne 'print "$1\n" if /REJECT: (.+)/' ai_output/*.txt | sort | uniq -c

Run with: bash process_results.sh

If you get stuck

Patterns for the challenges:

Ex 2: ack "port \d+" server.log
Ex 3: ack -iw "fox" animals.txt
Ex 4: ack -o "'[^']+'" server.log
Ex 5: rename 's/final_FINAL_v2/final/' final*
Ex 7: perl -ne 'print unless /INFO/' server.log
Ex 8: perl -F',' -ane '$s+=$F[2] if $.>1; END{print $s/3,"\n"}' scores.csv
Ex 9: perl -ne 'print "$_\n" while /(\d+)/g' server.log
Ex 10: perl -ne 'print "$1\n" if /REJECT: (.+)/' ai_output/*.txt | sort | uniq -c

Keep going

You now have the fundamentals. Practice daily on real tasks, not just exercises. Learn more Perl. One-liners are the gateway. Explore ripgrep (rg) for even faster searching. Check out sed and awk: different tools, overlapping uses. Bookmark regex101.com for testing patterns. These skills show up constantly in real talk demos.