Bash: check if a string contains text, digits, or a prefix (`[[ ]]`, globs, regex)

Most “bash string contains” tasks boil down to one of three checks: a literal substring, a pattern (digits, letters, “only numbers”), or a prefix/suffix on the string. Bash can do all of that inside [[ ... ]] with either glob patterns or a regex match operator (=~). For ordering and equality without pattern logic, see bash compare strings and bash compare numbers when you move from “contains” to “sorts before/after”.

Tested the [[ ... ]] snippets from this article on Ubuntu 25.04, kernel 6.14.0-37-generic, Bash 5.2.37. One note on locale is in the last section.


Bash: check if a string contains another string (substring)

The usual bash if string contains pattern is a glob on the left-hand side and a quoted needle so empty values or spaces do not break the match:

bash
haystack='foobar'
needle='oba'
if [[ $haystack == *"$needle"* ]]; then
  echo 'substring found'
else
  echo 'not found'
fi

That prints substring found. If needle is empty, the `` collapses in ways you rarely want—guard with [[ -n $needle ]] before testing.


Bash: check if a string contains a digit, or only digits

To answer bash check if string contains a digit anywhere, [[ =~ ]] is concise:

bash
VAR='test1234'
if [[ $VAR =~ [0-9] ]]; then
  echo 'contains at least one digit'
else
  echo 'no ASCII digits'
fi

That prints contains at least one digit. A plain hello run prints no ASCII digits.

For bash check if string is a number in the sense of “only digits” (an integer-shaped string, allowing a leading 0), anchor the regex:

bash
VAR='1234'
if [[ $VAR =~ ^[0-9]+$ ]]; then
  echo 'only digits'
else
  echo 'not only digits'
fi

42 prints only digits; 42a prints not only digits. You can spell the class as ^[[:digit:]]+$ if you prefer POSIX character classes.

These tests care about decimal digits in the string, not whether the value fits in an int for arithmetic—use $(( ... )) validation separately when you need numeric range checks.


Bash string starts with or ends with a prefix

bash string starts with checks are globs on the left:

bash
s='prefix_rest'
if [[ $s == prefix* ]]; then
  echo 'starts with prefix'
fi

Ends with uses a trailing glob:

bash
f='access.log'
if [[ $f == *.log ]]; then
  echo 'ends with .log'
fi

Both snippets print the success branch on the values shown.


Alphanumeric-only strings and “special” characters

To see if a value is letters and digits only (no spaces or punctuation), use [[:alnum:]] anchored to the ends:

bash
VAR='abc123'
if [[ $VAR =~ ^[[:alnum:]]+$ ]]; then
  echo 'alnum only'
else
  echo 'contains other characters'
fi

abc@123 hits the second branch. The inverse—bash check if string contains character classes outside alnum—is often written as “not alnum-only”:

bash
VAR='abc@123'
if [[ ! $VAR =~ ^[[:alnum:]]+$ ]]; then
  echo 'has non-alphanumeric characters'
fi

That prints has non-alphanumeric characters.


Vowels and other letter classes

A small bash check if string contains character example is vowel detection:

bash
VAR='Apple'
if [[ $VAR =~ [AEIOUaeiou] ]]; then
  echo 'contains a vowel'
else
  echo 'no vowels matched'
fi

That prints contains a vowel; rhythm prints no vowels matched with this simple ASCII set.


Locale, regex variables, and habits that save time

  • [[ string =~ regex ]] treats the right side as a regex unless it is stored in a variable—then the variable’s contents are the pattern. If you build patterns dynamically, keep them in a variable to avoid surprises with quoting.
  • Locale changes how [[:alnum:]] treats letters outside ASCII. For strict ASCII tests, run with LC_ALL=C for that snippet. On the test host, café matched ^[[:alnum:]]+$ under the default UTF-8 locale, but not when forced with LC_ALL=C—worth remembering if you script for international text.
  • For heavy validation (email, IDs), consider a small Python or grep -E helper; nested regex in Bash gets hard to read fast.

Summary

Use [[ $haystack == *"$needle"* ]] for the common bash string contains substring case, always quoting the needle. Use [[ $var =~ ... ]] when you need bash check if string contains a digit ([0-9]), bash check if string is number-like with ^[0-9]+$, or letter classes such as vowels. Use [[ $s == prefix* ]] or [[ $s == *.suffix ]] for bash string starts with or ends with checks. For “only letters and digits”, ^[[:alnum:]]+$ is the usual test, and negating it catches broader “non-alnum” content. Match your locale to the data you expect, especially outside ASCII.

Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)