Match text in Bash: filename globbing, the =~ regex operator inside [[ ]], and basic vs extended regular expressions with grep — knowing which is which.
Why: these two look similar but are different languages. A glob matches FILENAMES: * is any text, ? is one character, [abc] is a character set. A regex matches inside TEXT and is what grep and =~ use. Confusing them is a common source of "why didn't that match" frustration.
Globs — expanded by the shell into matching filenames
ls *.txt # every file ending in .txtls report-?.csv # report-1.csv, report-a.csv (one char)ls [abc]*.log # files starting with a, b, or cWhy: the =~ operator tests a string against an extended regular expression, right inside Bash — no grep needed. The captured groups land in the BASH_REMATCH array. Note: do not quote the pattern, or it is treated as literal text.
#!/usr/bin/env bash
read -r -p "Enter a date (YYYY-MM-DD): " input
if [[ "$input" =~ ^([0-9]{4})-([0-9]{2})-([0-9]{2})$ ]]; then
echo "year is ${BASH_REMATCH[1]}" # first capture group
else
echo "not a valid date"
fiNote: the pieces you reach for most. ^ start, $ end, . any character, * zero-or-more, + one-or-more, [0-9] a digit, [a-z] a letter, \. a literal dot. Anchoring with ^ and $ is what turns "contains" into "exactly matches".
#!/usr/bin/env bash
# A few patterns worth recognizing:
# ^error line starts with "error"
# failed$ line ends with "failed"
# [0-9]+ one or more digits
# ^\s*$ a blank line (only whitespace)
# \.log$ ends with a literal ".log"
email="ada@example.com"
[[ "$email" =~ ^[^@]+@[^@]+\.[a-z]+$ ]] && echo "looks like an email"Why: plain grep uses Basic Regular Expressions, where +, ?, |, and () must be backslash-escaped to act as operators — surprising everyone. grep -E (extended) makes them work without escaping. Reach for -E by default. Note: grep and the text pipeline live in the Linux course lesson on pipes & text processing.
Extended regex (-E): operators work without escaping
grep -E "warn|error" app.log # lines with either wordgrep -E "^[0-9]{3}-[0-9]{4}$" phones # match a phone format-o prints only the match; -i ignores case; -c counts lines
grep -Eoi "[a-z]+@[a-z.]+" contacts.txt