1. Overview

One of the most useful features of Bash is its support for conditional statements. Among these is the ternary operator or conditional operator, denoted by the ? symbol. The ternary operator returns different values based on the evaluation of a condition.

In this tutorial, we’ll discuss how to use the ternary operator in Bash. Further, we’ll look at equivalent constructs that use logical operators or if-else statements.

2. Ternary Operator

The ternary operator is a compact and efficient way to write conditional expressions. It’s a shorthand way of writing an if-else statement that returns a value.

In Bash, the syntax for the ternary operator occurs inside double parentheses which allow for arithmetic evaluation:

((condition ? value_if_true : value_if_false))

We’ll refer to the three operands respectively as expressions expr1, expr2, and expr3:

((expr1 ? expr2 : expr3))

The expression expr1 is first evaluated. If the result in Boolean is non-zero (true), then the interpreter evaluates expression expr2. Otherwise, it evaluates expr3.

3. Finding the Maximum Among Two Integers

Suppose we want to find the maximum of two integers a and b. We can either use a ternary expression to do so or use an equivalent construct via an if-else statement or logical operators.

3.1. Using a Ternary Expression

First, let’s see how we can set z to the maximum of a and b via a ternary expression:

$ a=1; b=2
$ z=$((a > b ? a : b))
$ echo "$z"
2

Here, the interpreter evaluates the first operand and determines that it’s false since a (1) isn’t greater than b (2). Therefore, the returned value is the third operand, b, which has a value of 2.

Alternatively, we can set the variable z directly within the double parentheses:

$ ((z = a > b ? a : b))
$ echo "$z"
2

Instead of using double parentheses for arithmetic evaluation, we can also assign the result of a ternary expression to a variable using the let command:

$ let z="(a > b) ? a : b"
$ echo "$z"
2
$ let "z = (a > b) ? a : b"
$ echo "$z"
2

Moreover, ternary expressions can generally be rewritten as if-else statements or using logical operators.

3.2. Equivalent if-else Statement

Let’s rewrite the ternary expression as an if-else statement:

$ if [ "$a" -gt "$b" ]; then z="$a"; else z="$b"; fi
$ echo "$z"
2

We use square brackets to test an expression. The -gt option inside the brackets stands for greater than, i.e., we’re testing if the value of a is greater than b.

3.3. Equivalent Expression Using Logical Operators

Alternatively, we can use logical operators && and || to rewrite our expression:

$ z=$([ "$a" -gt "$b" ] && echo "$a" || echo "$b")
$ echo "$z"
2

The entire expression in this case runs in a subshell.

However, we can further shorten the expression:

$ [ "$a" -gt "$b" ] && z="$a" || z="$b"
$ echo "$z"
2

This way, we don’t need to spawn a subshell for the assignment.

4. Ternary Expressions and Arithmetic Evaluation

It’s important to note that Bash’s ternary expressions are limited to arithmetic expressions only. However, we can always find a workaround by adding a subsequent if-else statement:

$ cat script.sh
x=17
output=$((x % 2 == 0 ? 1 : 0))
if [ "$output" -eq 1 ]; then
    echo 'The number is even'
else
    echo 'The number is odd'
fi

In this example, we’re using the ternary operator in combination with the modulo operator, %, to test whether the value of the variable x is even or odd. If the remainder of x is zero when divided by 2, the ternary operator returns the value 1. Otherwise, it returns 0.

Then, we use an if-else statement to check the value of output and print the appropriate message, which we wouldn’t be able to do with the ternary expression alone.

5. Nested Ternary Expressions

It’s also possible to nest ternary expressions. For example, we can construct a ternary expression to find the maximum among three integers a, b, and c:

$ a=1; b=2; c=3
$ echo $(( max = a > b ? ( a > c ? a : c) : (b > c ? b : c) ))
3

In this case, the second and third operands or the main ternary expression are themselves ternary expressions. If a is greater than b, then a is compared to c and the larger of the two is returned. Otherwise, b is compared to c and the larger is returned.

Numerically, since the first operand evaluates to zero (false), the interpreter evaluates the third operand and returns the value of c since b isn’t greater than c.

6. Order of Evaluation

The ternary operator associates from right to left:

(( expr1 ? expr2 : expr3 ? expr4 : expr5 ))

We can make the expression clearer by enclosing the third operand with single parentheses:

(( expr1 ? expr2 : ( expr3 ? expr4 : expr5 ) ))

The two expressions are equivalent, though the second is more readable than the first. In cases where expressions could be misinterpreted, it’s good practice to highlight operands with parentheses for better readability.

As an example, suppose we wish to compare two integers a and b. If a is larger than b, then a is returned, otherwise, the larger of integers b and c is returned:

$ a=1; b=2; c=3
$ echo $((a > b ? a : b > c ? b : c))
3

Since ternary expressions associate from right to left, we can highlight this fact:

(( a > b ?  a  : ( b > c ? b : c ) ))
(( 1 > 2 ?  1  : ( 2 > 3 ? 2 : 3 ) ))
   -----   ---    ---------------
   expr1  expr2        expr3

Since expr1 is false, expr3 is evaluated and the result is the value of c.

7. Conclusion

In this article, we’ve seen that conditional operators can simplify code and make it more compact. If used wisely, conditional operators can also make code easier to read and understand. We’ve also seen that we can construct equivalent expressions using if-else statements or logical operators.