GNU/Linux Programmer's Solver - Conditionals in Bash

Guess program in Bash. Conditionals, if, switch and constants
PROGRAMMING GUESS Bash
#!/bin/sh

readonly N=42
read -p "Guess the number ? " V

[ $V -lt 0 ] && (echo "Only positive numbers"; exit 1)

#if [ $V -lt 0 ]
#then
#    echo "Only positive numbers" 
#    exit 1
#fi


if [ $V -eq $N ]
then
    echo "Good job!"
else
    echo "Keep trying!"
    echo "The number is " $([ $V -lt $N ]  && echo "HIGHER" || echo "LOWER")
    # On fail show a hint
    H=$([ $((N-V)) -lt 0 ] && echo $((V-N)) || echo $((N-V)))

    echo -n "HINT : "
    if [ $H -lt 5 ] ; then echo "TOO HOT!";
    elif [ $H -lt 10 ] ; then echo "HOT";
    elif [ $H -lt 15 ] ; then echo "WARM";
    else echo "COLD"
    fi
fi

Bash, as you can see, is a totally different beast from the rest of the languages we’ve seen so far. While all the elements we’ve talked about so far can be easily identified, the syntax of each of them is quite different from what we’re used to.

The first thing we can observe is that Bash uses the keyword then to identify the main block of the expression. It also offers the else if option using the keyword elif as well as else as a final catch-all condition. Conditional blocks end with fi, which is nothing more than if reversed.

I’M A NEWBIE

Variables in bash scripts can be declared at any time without further ado. These variables are always strings and the way to access their content is to use the $ character as a prefix.

To use the values of variables as numbers, it is necessary to use programs like [ or expr.

The conditions are a bit peculiar for what we are used to. The reason is that Bash handles all its variables as strings of characters, and operators like -eq (equal) or -lt (less than) tell Bash to treat the parameters as numbers.

As you can see, these conditions must always be placed within square brackets… And watch out for the spaces before and after.

DID YOU KNOW

Yes, [ is a program, you can find it in /usr/bin. That’s why it’s necessary to leave a space between [ and the first parameter… Similarly, the ] character is used to indicate the end of the condition we want to evaluate and, for that same reason, it needs a space before it, it’s nothing more than another parameter we pass on the command line separated by spaces.

The Ternary Operator in bash can be simulated with the && and || operations. The first is a logical AND and the second an OR. When we connect two commands with &&, bash must ensure that both commands are executed (return a value of 0). So, if the first command fails, the second is not executed since the result will be false (the first has already failed).

OR works similarly, ensuring that at least one of the commands is executed, so if the first has been executed successfully, there is no need to execute the second.

I’M A NEWBIE

Bash defines a series of internal variables, such as $?, which returns the value returned by the last program executed. For example:

    $ ls /tmp
    (list of files in /tmp)
    $ echo $?
    0
    $ ls /a # Use any directory you know that doesn't exist
    ls: cannot access '/a': No such file or directory
    $ echo $?
    2

These are the values used by the [ program.

Using these two operators, we can simulate the ternary operator of other languages with expressions like:

[ CONDITION ] && INSTRUCTION-THEN || INSTRUCTION-ELSE

Bash starts executing the first program [ which evaluates the condition. If the condition is true [ returns 1 and as what follows is a && it will execute the next command, the INSTRUCTION-THEN. As what follows is an || and the first part has already been fulfilled… Bash does not need to calculate the second part of the OR.

If [ returns 0 (the condition is not met), Bash will skip the next instruction connected with &&, since it is impossible to ensure that both instructions can be executed correctly (the first has already failed). So it continues evaluating and encounters the ‘||’, since the first part of the ‘||’ is false, it evaluates the second to see if it can still meet the condition, effectively executing INSTRUCTION-ELSE.

That’s it. You might find it easier to write an if-then-else block after all. You can write a simple condition in a single line as follows:

if [ CONDITION ]; then INSTRUCTION-THEN; else INSTRUCTION-ELSE; fi

DID YOU KNOW?

The built-in command read allows us to read data from the user in our program. Using the -p flag, we can include a prompt (or a message to display to the user) to give them information about what type of information we expect. In bash, all variables contain strings, so no type conversion is necessary.

Bash also offers a switch-like statement to nest conditions. In this case, the format is as follows:

case $var in
  case1)
    commands
        ;;
  case2)
    commands
        ;;
  *)
    default-commands
        ;;
esac

The different cases in the case statement can be any type of string, including regular expressions.

case $H in
  [1-5])
    echo "Cualquier valor entre 1 y 5"
        ;;
  8?)
    echo "Ochentaitantos";
        ;;
  Linux*)
    echo "Cualquier cosa que empiece for Linux"
        ;;
  "6" | "7")
    echo "Cuatro o 5"
        ;;
   *)
     echo "Todo lo demás"
         ;;
esac

To declare constants in our shell scripts, we can use the readonly command, which will display an error and terminate our script if we modify one of those variables. This is the solution used in the example program at the beginning of the text.

bash allows us to declare read-only variables as follows:

declare -r N=42

To finish, note that in the program, we used parentheses (...) to group commands. Used without further ado, it will execute all the commands between the parentheses one after another as a subprocess, but if we prefix it with the $ sign, it will return the output of the programs as a string. You can see examples of the use of both cases in the example program.

Summary

  • Supports if ... then ...[else] ... fi

  • Supports a kind of ternary operator

    [ CONDITION ] && INSTRUCTION-THEN || INSTRUCTION-ELSE

  • Does not support booleans: ==0 -> FALSE and !=0 TRUE

  • Supports switch : case VAL in ; case REGEXP) code;; *) default;; esac

  • Constants with readonly command or declare -r (only bash).

Related Posts

GNU/Linux Programmer's Solver - Introduction

Programming exercises in 18 Programming Languages

Read

linuxprogramming

GNU/Linux Programmer's Solver - Hello World in Bash

Hello World program in Bash. Basic structure, comments and string literals

Read

PROGRAMMING BASH HELLO WORLD SHELL PROGRAMMING

GNU/Linux Programmer's Solver
Chapter 2 - Conditionals

Conditionals are the may way to add logic to your programs.

Read

PROGRAMMING HELLO WORLD

Return to Home Page