Course outline

Bash / Intermediate: reliable data and failure paths / Lesson 11

Choose the right test language

Distinguish test, Bash [[ ]], arithmetic conditions, shell patterns, and regular expressions without introducing parsing ambiguities.

About 4 min readContent reviewed
On this page

Lesson goals

  • Explain argument-based test versus Bash conditional syntax.
  • Control literal and pattern matching with quoting.
  • Validate external text before arithmetic evaluation.

The bracket command receives arguments

[ is a command-like interface requiring a closing ] argument; spaces are necessary to separate its words. Quote values so empty or spaced text does not change the argument structure. Prefer simple tests joined with shell && or || over ambiguous historical -a and -o forms. File tests observe a moment in time and cannot guarantee a later open succeeds. Use them for diagnostics or branch selection while still handling the real operation’s failure. A successful -f check is not authorization to trust the content of the file.

Bash conditionals suppress ordinary splitting

[[ ... ]] is Bash syntax with its own operators and expansion rules. Ordinary word splitting and filename expansion do not occur to its operands as they do in a simple command. This does not mean quoting never matters: quoting the right side of == changes pattern interpretation, and quoting a regular expression or part of it changes literal matching. Keep string comparison, pattern matching, and numeric comparison visibly distinct. [[ is not POSIX sh syntax, so use it only when Bash is the declared interpreter rather than advertising the script as universally portable.

bash Compare a shell pattern with literal text
value='report.txt'
pattern='*.txt'
if [[ $value == $pattern ]]; then printf 'pattern=yes\n'; fi
if [[ $value == "$pattern" ]]; then
  printf 'literal=yes\n'
else
  printf 'literal=no\n'
fi
Expected output
pattern=yes
literal=no

The unquoted pattern operand retains matching meaning within [[. Quoting it asks whether the value literally equals the characters asterisk-dot-txt.

Regular expressions have a separate grammar

The =~ operator uses extended regular-expression behavior supported by Bash’s implementation. Store a fixed expression in a variable for readability, then expand that variable unquoted on the regex side when regex meaning is intended. Quoting it can request literal matching instead. BASH_REMATCH stores the matched text and capture groups after a successful match and is global state, so copy needed captures before another match overwrites them. Anchor validation expressions when the whole input must conform. A substring match is not proof that the complete value has the required grammar.

bash Capture a validated synthetic identifier suffix
value='job-42'
regex='^job-([0-9]+)$'
if [[ $value =~ $regex ]]; then
  number=${BASH_REMATCH[1]}
  printf 'id=%s\n' "$number"
fi
Expected output
id=42

The anchors require the whole value to match. The captured digits are printed as text; no untrusted arithmetic evaluation is performed.

Arithmetic truth is not command success in disguise

(( expression )) evaluates Bash integer arithmetic and returns zero status when the expression’s value is nonzero. This reverses the intuition of a numerical zero meaning shell success. Increment and comparison expressions therefore interact with if, &&, and errexit. Operands can reference variables and evaluate expressions recursively, so validation must precede evaluation of external text. Decide accepted signs, leading zeros, range, and overflow behavior. Bash is not a decimal calculator with arbitrary precision. If numerical requirements exceed its model, delegate to a suitable tool rather than hide complexity in arithmetic expansion.

Test the grammar boundary and actual operation

A meaningful test set includes empty input, spaces, wildcard characters, regex metacharacters, leading dashes, malformed numbers, and valid edge values. Test both expected matches and expected rejections, not only one successful example. A file predicate should be followed by failure handling for the actual read or write because another process can change the object after the check. Keep match state out of unrelated globals when possible and document which helpers overwrite BASH_REMATCH. Tests should verify observable decisions and outputs rather than merely repeat the implementation’s own condition in another form.

Common errors and fixes

A quoted regex stops matching as expected

Why it happens
Quotation changed regex characters into literal text.
How to fix it
Use a fixed expression variable with deliberate regex expansion.
Prevent it next time
Test literal and pattern cases independently.

A substring is accepted as complete validation

Why it happens
The expression was not anchored to the whole input.
How to fix it
Define and anchor the complete grammar.
Prevent it next time
Include prefixed and suffixed invalid examples.

A file check is treated as a later-open guarantee

Why it happens
The object may change between check and use.
How to fix it
Handle the actual operation’s failure too.
Prevent it next time
Use predicates for decisions, not security guarantees.

Check your understanding

1. Why does [[ $name == "$pattern" ]] differ from [[ $name == $pattern ]]?

Show worked solution

Quoting the right operand makes the pattern value literal for that comparison. The unquoted form allows its shell-pattern metacharacters to match. Choose the behavior from the input contract and test a value containing a literal asterisk.

2. A regex captures a value, then another helper matches a different string. What should the caller preserve?

Show worked solution

Copy the needed BASH_REMATCH elements immediately after the first successful match. The second match can overwrite that global array. Prefer explicit returned values or local copies rather than a hidden dependency on the most recent regex anywhere in the call chain.

Key takeaways

  • Name the test grammar and choose quoting for that grammar.
  • Validate whole inputs and handle real operations separately.

Official references