Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A single character pattern in Bash is a globbing metacharacter used in pathname expansion and string matching that evaluates to exactly one arbitrary character. The primary operator for this is the question mark (?), while bracket expressions ([...]) provide constrained single-character matching.

The ? Metacharacter

The ? operator matches any single character in a string or filename. It requires exactly one character to be present; it evaluates strictly to a length of one and will not match zero characters or multiple characters.

# Evaluates true for: a1c, aBc, a_c

# Evaluates false for: ac, abbc
[[ $string == a?c ]]


# Expands to files with exactly one character between 'doc' and '.txt'
ls doc?.txt
Evaluation Rules:
  • Path Boundaries: When used in pathname expansion, ? will not match a directory separator slash (/).
  • Hidden Files: By default, ? will not match a leading period (.) representing a hidden file or directory. The shell option shopt -s dotglob must be enabled to override this behavior.
  • Null Byte: It cannot match the null character (\0), as Bash strings are null-terminated.

Bracket Expressions [...]

A bracket expression evaluates to exactly one character that exists within the enclosed set or range. Despite containing multiple characters inside the brackets, the entire construct represents only a single character position in the resulting match.

# Evaluates true if the string is exactly 'a', 'b', or 'c'
[[ $string == [abc] ]]


# Expands to files starting with a single digit in the ASCII range '0' through '9'
ls [0-9]*
Evaluation Rules & Pitfalls:
  • Collation and Locale (LC_COLLATE): In many default locales (e.g., en_US.UTF-8), bracket ranges like [A-Z] or [a-z] use dictionary sorting (aAbBcCdD...). Consequently, [A-Z] will unexpectedly match lowercase letters (except ‘a’), and [a-z] will match uppercase letters (except ‘Z’). To enforce strict ASCII byte-value sorting, developers must set LC_COLLATE=C or use POSIX character classes (e.g., [[:upper:]]).
  • POSIX Character Classes: Supports classes like [[:alpha:]] or [[:digit:]], which resolve to a single character match from within that class while remaining locale-aware and safe from range collation issues.
  • Negation: Prefixing the set with ! or ^ immediately after the opening bracket inverts the match, evaluating to exactly one character not present in the defined set.
# Evaluates true for any single character that is NOT 'a', 'b', or 'c'
[[ $string == [!abc] ]]
[[ $string == [^abc] ]]
Matching Literals Inside Brackets: Bash natively supports backslash escaping inside bracket expressions. Characters that normally possess special meaning within brackets (], -, ^, !) can be safely escaped with a backslash (\) to be treated as literal characters.
[[ $string == [a\]c] ]]  # Matches 'a', ']', or 'c'
[[ $string == [a\-c] ]]  # Matches 'a', '-', or 'c'
[[ $string == [\!abc] ]] # Matches '!', 'a', 'b', or 'c'
Alternatively, Bash also respects POSIX positional rules to match these characters as literals without escaping:
  • Literal ]: Placed as the first character in the set, or immediately following the negation operator ([]abc] or [!]]).
  • Literal -: Placed as the first or last character in the set ([-abc] or [abc-]).
  • Literal ^ or !: Placed anywhere except the first position ([ab!c^]).

Contextual Execution

Single character patterns are evaluated dynamically based on the syntax context:
  1. Pathname Expansion (Globbing): Evaluated against the file system. If no file matches the pattern, Bash leaves the pattern as a literal string by default (modifiable via shopt -s nullglob or failglob).
  2. Conditional Expressions ([[ ... ]]): Evaluated as a pattern matching operator against strings on the right side of the == or != operators.
  3. Case Statements: Evaluated against the test string to determine execution branching.

Escaping and Literals

To suppress the special meaning of single character patterns and treat them as literal characters outside of bracket expressions, they must be quoted or escaped using a backslash (\), single quotes ('...'), or double quotes ("...").

# Evaluates true only for the exact 5-character literal string "file?"
[[ $string == file\? ]]
[[ $string == "file?" ]]
[[ $string == 'file?' ]]

Extended Globbing (extglob)

When the extglob shell option is enabled (shopt -s extglob), Bash alters the behavior of ? when combined with parentheses. This creates a composite pattern that matches zero or one occurrence of a specified pattern list, deviating from the strict “exactly one character” rule of the standalone ?.
shopt -s extglob


# Evaluates true for "", "pattern1", or "pattern2"
[[ $string == ?(pattern1|pattern2) ]]
Master Bash with Deep Grasping Methodology!Learn More