1. Introduction

In this tutorial, we’ll discuss how relational operators work in case statements within a Bash script.

First, we’ll look at the syntax and an example using case. After that, we’ll discuss how we can use a pipe operator in case. Next, we’ll cover how AND works in combination with a relational operator in a case statement. Lastly, we’ll explore how we can utilize the ternary operator in a case statement.

2. The case Statement in Bash

The case statement in a Bash script simplifies conditional queries. A Bash case is used for conditional branching based on the value of an expression or a variable.

A Bash case statement is similar to switch-case statements in other programming languages such as C or Java. Both enable us to evaluate an expression or a variable and perform different actions based on the match cases.

2.1. case Syntax

Each case statement consists of an expression specified after the case keyword. expression refers to a value, variable, or an actual expression that’s being matched against pattern.

To elaborate, a case statement compares the value of expression against each pattern listed in case. When pattern is matched, case executes the corresponding block usually until a ;; construct:

case expression in
  pattern 1)
   statements
   ;;
  pattern 2)
   statements
   ;;
  pattern n)
   statements
   ;;
  *)
   statements
   ;;
esac

Unlike other languages, the syntax of Bash case statements doesn’t include the switch keyword.

2.2. case Example

Here, we’ll consider an example that matches the value of number entered by a user via the read command:

$ cat compareNumber.sh
#!/bin/bash
read -p "Enter a number" number
case $number in
  1) echo "You entered number 1";;
  2) echo "You entered number 2";;
  100) echo "You entered number 100";;
  *) echo "You entered a number";;
esac

In this instance, first, we acquired user input with read. Next, we performed a simple comparison using a case statement. The script then compares the value of number with the specific cases. It’s crucial to note that we’ve compared a single pattern here.

We can modify this example to compare a range of numbers. For this scenario, we’ll try writing a range of numbers in a case pattern:

$ cat compareRange.sh
#!/bin/bash
read -p "Enter a number" number
case
  [0-80]) 
   echo "the number is between 0 and 80";;
  [81-100]) 
   echo "the number is between 81 and 100";;
  [101-180]) 
   echo "the number is between 101 and 180";;
  *) 
   echo "the number is out of the range";;
esac

However, the above solution won’t work as the case statement isn’t capable of handling a character range. [0-80] is a character group and the numbers between […] are treated as separate characters by Bash. To compare numeric values, we can use the pipe operator (|), AND operator (&&), and ternary operator among others.

3. Using Pipe Operator for Arithmetic Comparison

As we mentioned in the previous section, the numbers between […] are treated as a character group instead of a numeric range in case statements.

To check for a range of numbers, the first method is to use a pipe operator within the pattern in a case block:

$ cat compareNumberRange.sh
#!/bin/bash
read -p "Enter a number: " number
case $number in
  [0-9]|[1-7][0-9]|80)
   echo ">=0<=80"
   ;;
  [8-9]|[1-9][0-9]|100)
   echo ">=81<=100"
   ;;
  [1-9][0-9]|[1-9][0-9][0-9]|120)
   echo ">=101<=120"
   ;;
  [1-2][0-9][0-9]|[1-2][0-9][0-9][0-9]|300)
   echo ">=121<=300"
   ;;
  *)
   echo "Number is out of range."
   ;;
esac

Here, we used the pipe operator | to check for different numerical patterns. For example, if we consider the first pattern, we’ve used [1-7][0-9] to match two-digit numbers between 10 and 79. In addition, we’ve mentioned the condition for digits 0-9 and 80 explicitly.

4. Using Pipe Operator for String Comparison

Apart from the arithmetic comparison, we can use a pipe operator to check for string values. For example, to print the official language of a country depending on the user input, we’ll use a | with string values in a case statement:

$ cat stringCase.sh
#!/bin/bash
echo -n "Enter the name of a country: "
read COUNTRY
echo -n "The official language of $COUNTRY is "
case $COUNTRY in
  Italy | "San Marino" | Switzerland | "Vatican City")
   echo -n "Italian"
   ;;
  Spain | Mexico | Argentina)
   echo -n "Spanish"
   ;;
  France | Belgium | Canada)
   echo -n "French"
   ;;
  Germany | Austria | Switzerland)
   echo -n "German"
   ;;
  China | Taiwan | Singapore)
   echo -n "Mandarin Chinese"
   ;;
  Russia | Belarus | Kazakhstan)
   echo -n "Russian"
   ;;
  Brazil | Portugal | Angola)
   echo -n "Portuguese"
   ;;
  India | Pakistan | Bangladesh)
   echo -n "Hindi"
   ;;
  *)
   echo -n "Unknown"
   ;;
esac

In this script, we use the pipe operator (|) operator to match a particular language to multiple country names.

In addition to the above example, we can also use | in case while searching for file types using pattern matching:

$ cat stringCase.sh
#!/bin/bash
read -p "Enter a filename: " filename
case $filename in
  *.txt) 
   echo "Text file";;
  *.jpg | *.png | *.gif) 
   echo "Image file";;
  *.mp3 | *.wav) 
   echo "Audio file";;
  *.docx | *.pdf) 
   echo "Document file";;
  *) 
   echo "Unknown file type";;
esac

The above script verifies the file type based on the user input, stored in the variable filename. This variable is used as an expression within a case statement, where it is compared against a specific pattern.

The first pattern checks for the .txt extension categorizing it as a text file. The pattern *.jpg | *.png | *.gif matches files with .jpg, .png, or .gif extensions, categorizing them as image files. Next, we have the *.mp3 | *.wav pattern which categorizes files as audio files. Moreover, the pattern *.docx | *.pdf matches files with .docx or .pdf extensions, categorizing them as document files.

Lastly, the *) wildcard matches any other file type indicating an unknown file type.

5. Using AND Operator (&&)

We can also add conditions in the expression part of the case statement in Bash. Usually, to compare multiple values, we use relational operators in the pattern part of the case block. However, Bash also enables us to add conditions in the expression part:

$ cat compareNumberAND.sh
#!/bin/bash
read -p "Enter a number" number
case $((
  (number >= 0 && number <= 80) * 1 +
  (number > 80 && number <= 100) * 2 +
  (number > 100 && number <= 120) * 3 +
  (number > 120 && number <= 300) * 4)) in
  (1) 
    echo "The number is >=0 and <= 80";;
  (2) 
    echo "The number is > 80 and <= 100";;
  (3) 
    echo "The number is > 100 and <= 120";;
  (4) 
    echo "The number is > 120 and <= 300";;
  (0) 
    echo "None of the above";;
esac

In this example, we’ve used the arithmetic expression ((…)) with the relational operators and && to evaluate the value of number. Each condition inside ((…)) evaluates to either 0 or 1*.* Furthermore, we’ve multiplied the condition with a specific factor to assign a unique numerical value to each range, thereby identifying it. Lastly, the result is matched against different values within each case statement.

6. Using Ternary Operator

Similar to the AND operator in case, we can use the arithmetic expression with a ternary operator.

For this scenario, we’ll modify the logic in ((…)) to use a ternary operator for comparison:

$ cat compareNumberTernary.sh
#!/bin/bash
read -p "Enter a number" number
case $((
  number >= 0 && number <= 80 ? 1 :
  number > 80 && number <= 100 ? 2 :
  number > 100 && number <= 120 ? 3 :
  number > 120 && number <= 300 ? 4 : 0)) in
  (1) 
   echo "Number is >= 0 and <= 80";;
  (2) 
   echo "Number is > 80 and <= 100";;
  (3) 
   echo "Number is > 100 and <= 120";;
  (4) 
   echo "Number is > 120 and <= 300";;
  (0) 
   echo "Number is out of range";;
esac

In the above script, we’ve included the conditional ternary operator (? :) to assign the appropriate numerical value to each range instead of multiplying a condition output by a number.

7. Conclusion

In this article, we’ve discussed various examples using relational operators in case statements within Bash.

Firstly, we discussed arithmetic expressions to determine if a number falls within a specific range. We also explored how we can compare strings in a case statement. Lastly, we implemented the branching logic in case using a ternary operator.

By leveraging these techniques, we can use a case statement effectively to handle different scenarios involving relational operators and ranges.