Shell Scripting 101

Shell Scripting 101

We've talked about Linux and some basic bash commands in the past. But sometimes the job of a system administrator is lengthy and repetitive. This is where shell scripts come in really handy. Shell scripts is a program that includes a sequence of shell commands. Conceptually, shell scripts seem to look like programming, it actually an automated execution of other programs, and is meant to be run on the Linux kernel (Batch files for Windows).

P/S: Since this is just a basic overview of shell scripting, each of the following topics will not have an in-depth explanation, but only a walkthrough.

Hello, World!

Let's take a look at an easy example of a shell script.

#!/bin/bash

echo "Who are you?"
read NAME
echo "Welcome, $NAME"

The first line is the shebang interpreter directive. This indicates the OS to load the bash interpreter that is located inside the /bin directory and runs the script as bash commands.

Next, we'll be using a couple of built-in bash commands:

  • read: prompts user for input
  • echo: prints string output

The third line the echo command is called to print out the string "Who are you?" to the CLI. It seems like the program is stuck here, this is because the read command is waiting for a user input. So, if I enter D3LT4, it will pass it to the NAME variable. Finally, it will print out Welcome, D3LT4.

There you have your first bash script. Is it too easy? Let's go a little deeper.

Guess the Number (Easy)

Let's write a simple number guessing game with bash. Don't panic yet, as longs as you know the rules and logic of the game, you could write it easily.

#!/bin/bash

ANS=34
LOSE=true

function game(){
    if (($NUM < $ANS)); then
        echo "$NUM is smaller than the answer"
    elif (($NUM > $ANS)); then
        echo "$NUM is larger than the answer"
    elif (($NUM == $ANS)); then
        echo "You've got it!"
        LOSE=false
    else; then
        echo "C'mon, be serious..."
    fi
}

while $LOSE; do
    echo "Please guess a number from 1 to 50"
    read NUM
    game $NUM $ANS $LOSE
done

Variables

We've mentioned about variables in the previous example. But what's a variable? A variable is a data that has a name (identifier) and value. Values could either be a number, strings, boolean (true or false) or an array etc. In bash, variable names are case-sensitive, capitalized by convention and should not start with a digit. As shown in line 3 and 4, we assign variables through the equal (=) sign, quotes (", ') are used for declaring strings (more on that in future posts). Note that putting <spaces> beside the equal sign will cause errors. When calling a variable, we add a dollar ($) sign before the variable name.

So, first of, we assigned the ANS to be a number (34) and the LOSE a boolean (true), the boolean is used to identify if the user has guessed our number correctly.

Functions

Next, we declare the logic of our game with a function. Functions are basically a set of commands that could run when being called. Here the function is declared explicitly, it could also be declared implicitly game(). Some conventions recommend to add an underscore before declare functions. The content of the function is written within the { } brackets, and indented for better readability.

if-else Conditional Statements

Inside the game() function is a if-else conditional statement. Basically, if the statement is true, it will run the following chunk of code below it; or else, it will not run until it finds an acceptable statement. So now to the logic our game:

if the given $NUM is smaller than the $ANS,
    it will prompt the user that the $NUM is smaller than the answer;
  or else, if the given $NUM is larger than the $ANS,
    it will prompt the user that the $NUM is larger than the answer;
  or else, if the given $NUM is equal to (==) $ANS,
    it will indicate the user has won, and set the $LOSE boolean to be false;
  or else, if the user inserts something else,
    it will prompt the user to enter something that is meaningful.
fi indicates the end of the if-else conditional statement.

while Loop

A function will not run unless it is being called, and we haven't call our game() function yet. Now, the our game ends when the user has won ($LOSE==false). So, we call a while loop. This loop will run indefinitely when the condition is true and only ends if it's condition becomes false. So

while the user is $LOSE-ing, do the following:
    it will prompt the user to insert a number from 1 to 50,
    the OS then assigns the input of the user to the variable $NUM,
    and now passes the variables $NUM $ANS $LOSE into the game()
done indicates the end of the while loop.

There, a simple game written in bash. But could we make it a little bit harder?

Guess the Number (Hard)

#!/bin/bash

ANS=34    # This is the answer
CHANCES=3     # No. of Chances

function game(){
    if (($NUM!=$ANS))&&(($ATT<3)); then
        if (($NUM < $ANS)); then
            echo "$NUM is smaller than the answer"
        elif (($NUM > $ANS));then
            echo "$NUM is larger than the answer"
        fi
    elif (($NUM == $ANS)); then
        echo "You've got it!"
        exit
    elif (($NUM!=$ANS))&&(($ATT==3)); then
        echo "You've lost QQ"
    else; then
        echo "C'mon, be serious..."
    fi
}

for((ATT=1; ATT<=$CHANCES; ATT++)); do
    echo "Attempt: $ATT"
    echo "Please guess a number from 1 to 50"
    read NUM
    game $NUM $ANS $ATT
done

Here we have an advanced version of our game. The user is limited to only three attempts to answer our question. The logic of our game() function now has a few changes.

Comments

Comments start with a hash (#) sign, the code behind it is a comment, it would
be ignored by the program. Comments are used for explaining a line/chunk of
code. It is highly recommended for programmers to write comments so reduce the
burden of code readability.

Operators

We mentioned about conditions in statements and in loops. Logical and comparison
operators are basically used to determine if the conditions is either TRUE or
FALSE (a.k.a boolean values). There are also increment/decrement operators, as
seen in line 23, there is a weird ATT++ at the end of the closed brackets. The
++ is an increment operator, it is basically a shorthand for x=x+1. There is a
difference between ATT++ and ++ATT, the former being a postfix, where the value is returned before increment; and latter being pre-fix, where the value is
returned after increment. Here's a small list of some basic operators:

Syntax Meaning
a+=b a=a+b
a-=b a=a-b
a*=b a=a*b
a/=b a=a\b
a%=b a=a%b (% computes the remainder after dividing a by b
a++ a=a+1 (pre-increment)
++a a=a+1 (post-increment)
a-- a=a-1 (pre-decrement)
--a a=a-1 (post-decrement)
a&&b a AND b
`a
!a NOT a
a==b a IS EQUAL b
a!=b a IS NOT EQUAL b

for Loop

If we want to limit the number of times the user could input, we could use a for loop. A for loop consist of three components: the iterator initialization, the condition, the afterthought. What we have here in our code at line 23, is the number of ATTempts. While the number of ATTempts is lower than CHANCES, the chunk of code below will be run. And every time after the code has run, the number of ATTempts will increase by 1. When the value of ATT reaches 4, it would then break the loop.

Conclusion

This game might seem useless in terms of practical application, but there are some basic scripting/programming concepts that are used in all of programming languages. These programming syntax are also very helpful when you want to do tasks like creating users from a .csv list, expire all users passwords etc. Learning these fundamental tools for automating these tasks would save a lot of time for an administrator.