#!/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
fiBash, 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
[orexpr.
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 $? 2These 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-ELSEBash 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; fiDID YOU KNOW?
The built-in command
readallows us to read data from the user in our program. Using the-pflag, we can include aprompt(or a message to display to the user) to give them information about what type of information we expect. Inbash, 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
;;
esacThe 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"
;;
esacTo 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=42To 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] ... fiSupports a kind of ternary operator
[ CONDITION ] && INSTRUCTION-THEN || INSTRUCTION-ELSEDoes not support booleans:
==0 -> FALSE and !=0 TRUESupports
switch:case VAL in ; case REGEXP) code;; *) default;; esacConstants with
readonlycommand ordeclare -r(onlybash).