How to Compare Strings in Bash

It is a normal or I would say daily use case for a Linux developer to work on a script which requires comparison of strings. But I have seen many people tend to get confused between strings and integers. So before we go ahead and learn about string comparison in bash, let us understand the basic different between bash and integer value.

 

Difference between Integers and Strings

Now in bash we have strings and integers. So any text provided under single quotes ('') or double quotes ("") is considered as string. So even if you provide a numerical value under single or double quotes which by default should be an integer but due to the quotes it will be considered as string.

NOTE:

integer and string use a different set of comparison operators.

 

Let us take some examples to understand the difference between string and integer in bash:

For examples:

VAL="text" => Here text is a string
VAL="10"   => Here 10 is a string even though this is an integer as it is provided with double quotes
VAL='11'   => Again for the same reason 11 will be considered as string as it is under single quotes
VAL=11     => Here 11 is integer so this needs separate handling for bash string comparison

 

Comparison operators for strings

First let us understand the different comparison operator available for sting comparison in bash and shell script.

NameOperator syntaxSyntax with single bracketSyntax with double bracketsComment
is equal to= (or) ==[ "string1" = "string2" ][[ "$string1" == "string2" ]]Returns TRUE if both the operands are equal
is not equal to!=[ "string1" != "string2" ][[ "string1" != "string2" ]]Returns TRUE if both the operands are NOT equal
is less than<[ "string1" \< "string2" ][[ "string1" < "string2" ]]Use escape character for the operator in single bracket
Returns TRUE if the right operand is considered lower than the left operand
The comparison is done using ASCII alphabetical order
is greater than>[ "string1" \> "string2" ][[ "string1" < "string2" ]]Use escape character for the operator in single bracket
Returns TRUE if the right operand is considered higher than the left operand
The comparison is done using ASCII alphabetical order
zero string length-z[ -z "string2" ][[ -z "string2" ]]Returns TRUE if the provided String has zero length i.e. null value
non zero length-n[ -n "string2" ][[ -n "string2" ]]It is IMPORTANT that the string is under inverted commas
Returns TRUE if string is non-zero i.e. not null

 

Check if Strings are Equal

Bash compares strings by length and each character match. For example in this shell script I have defined both variables with same string

VAR1="golinuxcloud"
VAR2="golinuxcloud"

if [[ "$VAR1" == "$VAR2" ]];then
   echo "exit status: $?"
   echo "$VAR1 is equal to $VAR2"
else
   echo "exit status: $?"
   echo "$VAR1 is NOT equal to $VAR2"
fi

The output from this script shows that the first condition returns TRUE with exit status as zero so both strings are considered EQUAL

exit status: 0
golinuxcloud is equal to golinuxcloud

If we run this in DEBUG mode (the best thing I like about shell scripts)

+ VAR1=golinuxcloud
+ VAR2=golinuxcloud
+ [[ golinuxcloud == \g\o\l\i\n\u\x\c\l\o\u\d ]]
+ echo 'exit status: 0'
exit status: 0
+ echo 'golinuxcloud is equal to golinuxcloud'
golinuxcloud is equal to golinuxcloud

As you see, bash is comparing both the string's length and each character before returning TRUE status

 

Check if Strings are NOT Equal

We will make some change in one of our variables and then perform the string comparison

VAR1="golinuxcloud"
VAR2="website"

if [[ "$VAR1" != "$VAR2" ]];then
   echo "exit status: $?"
   echo "$VAR1 is NOT equal to $VAR2"
fi

The output of this script shows the first condition returns TRUE with exit status as zero so both strings are not equal

exit status: 0
golinuxcloud is NOT equal to website

 

Compare strings using ASCII order

I have personally not used this in my career till now, I would be interested to know if any my readers have any use case to use such comparison for strings
I have taken two variables with two different strings

VAR1="A"
VAR2="B"

if [[ "$VAR1" > "$VAR2" ]];then
   echo "exit status: $?"
   echo "$VAR1 is greater than $VAR2"
elif [[ "$VAR1" == "$VAR2" ]];then
   echo "exit status: $?"
   echo "$VAR1 is equal to $VAR2"
else
   echo "exit status: $?"
   echo "$VAR1 is lesser than $VAR2"
fi

The output of this script would be

exit status: 1
A is lesser than B

Because as per ASCII code Letter A has ASCII code of 065 while Letter B has 066 so Letter A is considered lesser than B

NOTE:

Here you must use escape character for greater than (>) and less than (<) sign if you are using single braces [ ]

 

Check if string is empty

This is one of the most used operator in real time production environment where we are collecting output from some command into a variable and want to make sure that the variable is not empty i.e. it was able to collect the command output

In this script I am trying to get PID of a dummy process so it is expected that the variable will be empty

VAR=`pidof dummy`

if [ -z "$VAR" ]; then
  echo "exit status: $?"
  echo "\$VAR is null."
else
  echo "exit status: $?"
  echo "\$VAR is NOT null."
  echo "value: $VAR"
fi

Output from this script confirms that our string is empty and returns TRUE

exit status: 0
$VAR is null.

In this script I will look for PID of java process

VAR=`pidof java`

if [ -z "$VAR" ]; then
  echo "exit status: $?"
  echo "\$VAR is null."
else
  echo "exit status: $?"
  echo "\$VAR is NOT null."
  echo "value: $VAR"
fi

Output from this script tells us that the VAR string is not empty and returns FALSE

exit status: 1
$VAR is NOT null.
value: 10592

 

Check if string is non-zero or not-null

We can use the same script to verify if the variable is non-zero.
The difference is with -z we get zero exit when string has no value while the just opposite with -n which will return zero exit status if the string is non-zero

VAR=`pidof java`

if [ -n "$VAR" ]; then
  echo "exit status: $?"
  echo "\$VAR is NOT null."
else
  echo "exit status: $?"
  echo "\$VAR is null."
  echo "value: $VAR"
fi

The output from the script

exit status: 0
$VAR is NOT null.

 

Shell Script: string comparison operator examples

We will check some examples to understand and learn bash string comparison.

Here I have created a single script which will use all the bash string comparison operators we learned about in a while loop so that I don't have to write separate function to demonstrate an example. This loop will continue to run unless I manually send an interrupt signal to the script:

# cat /tmp/bash_compare_strings.sh
#!/bin/bash
# Bash Compare Strings

# Run the script untill manually interrupted
while true; do

   # Collect VAR1 and VAR2 value from end user
   read -r -p "Enter VAR1 value: " VAR1
   read -r -p "Enter VAR1 value: " VAR2

   # Check if $VAR1 value is less that $VAR2
   if [[ "$VAR1" < "$VAR2" ]];then 
      echo "$VAR1 is less than $VAR2" 
   # Check if $VAR1 value is greater than $VAR2 
   elif [[ "$VAR1" > "$VAR2" ]];then
      echo "$VAR1 is greater than $VAR2"
   # Check if $VAR1 is equal to $VAR2	  
   elif [[ "$VAR1" == "$VAR2" ]];then
      echo "$VAR1 is equal to $VAR2"
   # Chcek if $VAR1 is not equal to $VAR2	  
   elif [[ "$VAR1" != "$VAR2" ]];then
      echo "$VAR1 is NOT equal to $VAR2"
   else
   # If none of the above condition matches
      echo "Unable to get the status"
  fi
done

Now we will give different values to VAR1 and VAR2 in this script and check the exit status. If you observe I have placed both variables under double quotation mark so even if you give numbers as an input to this script, they will be considered as strings.

Provide executable permission to the script

# chmod u+x /tmp/bash_compare_strings.sh

Let us execute our script to learn more about bash compare strings operator:

# /tmp/bash_compare_strings.sh
Enter VAR1 value: deepak
Enter VAR1 value: deepak
deepak is equal to deepak        <- We know both the strings are same

Enter VAR1 value: deepak
Enter VAR1 value: amit
deepak is greater than amit      <- deepak has more number of char compared to amit

Enter VAR1 value: amit
Enter VAR1 value: deepak
amit is less than deepak         <- amit has less number of char compared to deepak

Enter VAR1 value: 100
Enter VAR1 value: 100
100 is equal to 100              <- both the strings are same

Enter VAR1 value: deep100
Enter VAR1 value: deep101
deep100 is less than deep101     <- we have combined text with number. deep is same in both variables but 100 is less than 101

Enter VAR1 value: deep100
Enter VAR1 value: amit101
deep100 is greater than amit101  <- This depends on the combination of ASCII code value

 

Perform regex and pattern (=~) match for strings

We will check some more examples to compare bash regex match and bash pattern match. Here I have written a one liner shell script to check for bash regex match and bash pattern match.

[root@controller ~]# [[ "my name is deepak prasad" =~ "prasad"$ ]] && echo "bash regex match" || echo "bash regex nomatch"
bash regex match

We can also break this into multi line script which will be easier to understand for new comers

if [[ "my name is deepak prasad" =~ "prasad"$ ]]; then
   echo "bash regex match"
else
   echo "bash regex nomatch"   
fi

Here we use =~ instead of == to match a pattern and dollar $ sign to match the last word of the string. Now since "prasad" is the last word in my name is deepak prasad hence the bash pattern match is successful.

Similarly I check the for starting word using ^ in my string, now since my is the starting word in my name is deepak prasad the bash pattern match is successful.

[root@controller ~]# [[ "my name is deepak prasad" =~ ^"my" ]] && echo "bash regex match" || echo "bash regex nomatch"
bash regex match

We can also look out for certain word within a string without any regex as shown below. Since deepak word is present in my name is deepak prasad, the bash pattern match is successful

[root@controller ~]# [[ "my name is deepak prasad" =~ "deepak" ]] && echo "bash regex match" || echo "bash regex nomatch"
bash regex match

By default if we use "is equal to" for the below check then it says "nomatch" as with == the shell will try to match character to character for both the variables due to which the check fails

[root@controller ~]# [[ "my name is deepak prasad" == "deepak" ]] && echo "bash regex match" || echo "bash regex nomatch"
bash regex nomatch

So we use wildcard (*) regex to match the string to ignore starting and ending text, the bash regex match is successful.

[root@controller ~]# [[ "my name is deepak prasad" == *"deepak"* ]] && echo "bash regex match" || echo "bash regex nomatch"
bash regex match

 

Conclusion

Bash is still one of the most used programming language across industry although it is being taken over by Python, Go and other languages which serve more advantage but I still feel it your script contains more of system commands then bash is still the preferred language for Administrators and Developers. In this tutorial guide we learned about different string comparison operators, performing regex and pattern match for strings using different examples.

Lastly I hope the steps from the article to perform string comparison in shell scripts on Linux was helpful. So, let me know your suggestions and feedback using the comment section.

 

References

I have used below external references for this tutorial guide
Comparison Operators
ASCII Binary Character Table

 

Leave a Comment

Please use shortcodes <cmd>your code</cmd> for syntax highlighting when adding code.