How to Tell If a Bash String Contains a Substring on Linux

Linux laptop showing a bash prompt

Sometimes in Linux scripts, you want to know if a string of text contains a specific, smaller string. There are many ways to do this. We show you some simple, reliable techniques.

Why Is This Useful?

Searching a string for a smaller substring is a common requirement. One example would be reading text from a file or from human input and searching the string for a specific substring so that your script can decide what to do next. It might be looking for a label or device name in a configuration file or a command string in a line of input from a user.

Linux users are blessed with any number of utilities for manipulating text. Some are built into the Bash shell, others are provided as standalone utilities or applications. There’s a reason Unix-derived operating systems are richly served with string manipulation capabilities.

Some things that appear to be files are not simple files. They’re special files representing things like hardware devices and sources of system information. The abstraction performed by the operating system gives them the appearance and characteristics of files. You can read information from them—as text, naturally—and in some cases write to them, but they’re not ordinary files.

Text is also used as the input and output for commands in a terminal window. This allows the redirection and piping of input and output. That functionality underpins the ability to chain sequences of Linux commands together, passing the output from one command as the input to the next.

Regardless of its origins, searching the text we receive for a significant word, command, label, or some other indicator is a standard part of dealing with text-based data. Here is a collection of simple techniques you can include in your own scripts.

Finding Substrings With Bash Builtins

The double brackets[[...]]” string comparison test can be used in if statements to determine if one string contains another string.

Copy this script into an editor, and save it to a file called “double.sh.”

#!/bin/bash

if [[ "monkey" = *"key"* ]]; then
  echo "key is in monkey"
else
  echo "key is not in monkey"
fi

You’ll need to make the script executable with the chmod command. This is a step that’s always required to make any script executable. You’ll need to do this each time you create a script file. Substitute the name of the appropriate script in each case.

chmod +x double.sh

making a script executable with chmod

Let’s run the script.

./double.sh

Running the double.sh script

This works because the asterisk ” * ” represents any sequence of characters, including no characters. If the substring “key” is located within the target string, with or without any characters in front or behind it, the test will return true.

In our example, there are characters in front of the substring. These are matched by the first asterisk. There are no letters behind the substring but, because an asterisk also matches no characters, the test still passes.

For flexibility, we can modify our script to handle variables instead of literal strings. This is script “double2.sh.”

#!/bin/bash

string="Monkey"
substring="key"

if [[ $string = *$substring* ]]; then
  echo "$substring was found in $string"
else
  echo "$substring was not found in $string"
fi

Let’s see how that runs.

./double2.sh

Running the double2.sh script

This works in the same way, with the advantage that we can use variable names instead of literal strings. Turning our little solution into a function will provide the most flexibility.

This is script “double3.sh.”

#!/bin/bash

shopt -s nocasematch

string="Monkey"
substring="Key"
capital="London"

check_substring ()
{
if [[ $1 = *$2* ]]; then
  echo "$2 was found in $1"
else
  echo "$2 was not found in $1"
fi
}

check_substring "Monkey" "key" 
check_substring $string $substring
check_substring $string "banana"
check_substring "Wales" $capital

We call our check_substring function using a mix of variables and literal strings. We used shopt with its -s (set) option to set nocasematch, to make the matches case-insensitive.

Here’s how it runs.

./double3.sh

Running the double3.sh script

We can use the trick of wrapping the substring in asterisks in case statements, too. This is “case.sh.”

#!/bin/bash

shopt -s nocasematch

string="Wallaby"
substring="Wall"

case $string in

  *$substring*)
    echo "$substring was found in $string"
    ;;

  *)
    echo "Nothing matched: $string"
    ;;
esac

Using case statements instead of very long if statements can make scripts easier to read and debug. If you needed to check whether a string contained one of many possible substrings, the case statement would be the best choice.

./case.sh

Running the case.sh script

The substring is found.

Finding Substrings With grep

Beyond the Bash builtins, the first text search tool you’ll probably reach for is grep. We can use grep‘s innate ability to search for a string within a string to look for our substrings.

This script is called “subgrep.sh.”

#!/bin/bash

string="porridge pot"
substring="ridge"

if $(echo $string | grep -q $substring); then
  echo "$substring was found in $string"
else
  echo "$substring was not found in $string"
fi

The script uses echo to send the string into grep, which searches for the substring. We’re using the -q (quiet) option to stop grep writing anything to standard output.

If the result of the commands inside the parentheses “(...)” equals zero, it means a match was found. Because zero equates to true in Bash, the if statement is satisfied and the then clause is executed.

Let’s see what its output is.

./subgrep.sh

Running the subgrep.sh script

Finding Substrings With sed

We can use sed to find a substring, too.

By default, sed prints all text that is fed into it. Using sed -n prevents this. The only lines that are printed are matching lines. This expression will print any lines that match or contain the value of $substring.

"/$substring/p"

We feed the value of $string into sed using a here redirect, <<<. This is used to redirect values into a command in the current shell. It doesn’t invoke a subshell in the way that a pipe would.

The first -n is the test. It will return true if the output from the sed command is non-zero. The only way the output from sed can be non-zero is if a matching line was found. If that’s the case, $substring must have been found in $string.

This is “subsed.sh.”

#!/bin/bash

string="Sweden"
substring="eden"

if [ -n "$(sed -n "/$substring/p" <<< $string)" ]; then
  echo "$substring was found in $string"
else
  echo "$substring was not found in $string"
fi

We get the expected response when we run the script.

./subsed.sh

Running the subsed.sh script

We can test the logic of the script by editing the value of $substring so that the comparison fails.

./subsed.sh

Running the subsed.sh script with an unmatched substring

Stop Searching, Found It

Other tools can find substrings, such as awk and Perl but a simple use case like finding a substring doesn’t warrant their extra functionality nor the added complexity. In particular, using the Bash builtins to search for substrings is fast, simple, and doesn’t require external tools.

Original Article