If your first Bash script was like learning to walk in a straight line, it’s now time to learn how to dance. A simple script executes commands one after another, a predictable path.

But a truly powerful script can think, decide, and react. It can choose its own path based on changing conditions. This guide will teach you how to breathe life and intelligence into your scripts. We will turn your linear command sequences into dynamic, decision making programs.

Understanding Variables and User Input

Before a script can make a decision, it needs information. Just like we use our memory, a script uses variables to store information. Think of a variable as a labeled box where you can put a piece of data, like a name or a number, to use later.

Creating a variable is simple. You pick a name (traditionally in uppercase) and assign a value to it with the equals sign. Remember, no spaces around the equals sign!

GREETING="Hello there"
USER_COUNT=10

To use the value inside the box, you put a dollar sign $ in front of its name.

echo $GREETING
echo "We have $USER_COUNT users online."

That's great for predefined data, but what if you want your script to be interactive? You can ask the user for information using the read command. It pauses the script, waits for the user to type something and press Enter, and then stores that input in a variable.

Let’s make it more user friendly by adding a prompt with the read -p option.

#!/bin/bash
read -p "Please enter your name: " USER_NAME
echo "Welcome to the world of scripting, $USER_NAME!"

When you run this, it will politely ask for your name and then greet you personally. Your script is no longer just talking; it’s listening.

The Power of Exit Codes

Every command you run in Bash sends back a secret signal when it finishes. This signal is a number called an exit code, and it reports whether the command was successful. By convention, an exit code of 0 means "everything went perfectly." Any other number, from 1 to 255, means something went wrong.

How do you see this secret signal? Bash stores the exit code of the very last command in a special variable: $?.

Let's try it. The grep command searches for text in a file. It returns 0 if it finds the text and 1 if it doesn't.

First, create a file named food.txt containing the word "pizza".

echo "pizza" > food.txt

Now, search for "pizza" and immediately check the exit code.

grep "pizza" food.txt
echo $?

The output will be 0 (success). Now search for something that isn't there.

grep "sushi" food.txt
echo $?

This time the output will be 1 (failure). This little number is the bedrock of decision making. You can use it to check if a file was copied correctly, if a server is reachable, or if a program ran without errors.

Making Decisions with if, elif, and else

Now that we have information (from variables) and a way to judge success (with exit codes), we can finally make decisions. The if statement is the fundamental tool for this. It checks if a certain condition is true and, if it is, executes a block of code.

The structure looks like this:

if [[ condition ]]; then
  # code to run if condition is true
fi

The [[ ... ]] are special test brackets in Bash. Let's build a script that checks if a user is the root user, the superuser of the system.

#!/bin/bash
if [[ $USER == "root" ]]; then
  echo "You have super powers!"
fi

What if you want to do something else if the condition is false? That’s what else is for.

#!/bin/bash
if [[ $USER == "root" ]]; then
  echo "You have super powers!"
else
  echo "You are a regular user. Welcome!"
fi

But what if you have more than two possibilities? You can chain conditions together with elif (which means else if).

#!/bin/bash
read -p "Enter a number: " NUMBER

if [[ $NUMBER -gt 100 ]]; then
  echo "That's a big number!"
elif [[ $NUMBER -lt 10 ]]; then
  echo "That's a small number."
else
  echo "That's a number in the middle."
fi

Notice we used -gt (greater than) and -lt (less than) for comparing numbers. For numbers, you use special flags like -eq (equal), -ne (not equal), -gt (greater than), and -ge (greater than or equal to). For text, you use == and !=.

Using case Statements for Cleaner Choices

When you have one variable that you need to check against many possible values, a long series of if and elif statements can get messy. The case statement is a much cleaner and more elegant solution. Think of it like a receptionist routing a call based on the extension dialed.

It checks a variable against different patterns.

#!/bin/bash
read -p "What action would you like to perform? (start/stop/restart): " ACTION

case "$ACTION" in
  start)
    echo "Starting the service..."
    ;;
  stop)
    echo "Stopping the service."
    ;;
  restart)
    echo "Restarting the service."
    ;;
  *)
    echo "Sorry, that is not a valid action."
    ;;
esac

Each possible value is a pattern followed by a ). The code for that choice runs until the ;;. The * pattern is a wildcard that catches anything that didn't match the other options, acting like a final else.

Combining Commands with Logical Operators

Sometimes you want to run a command only if another one succeeds or fails. Bash gives you two incredibly powerful logical operators for this: && (AND) and || (OR).

  • The AND Operator: &&

This operator links commands together. The command on the right of && will only run if the command on the left is successful (returns an exit code of 0).

A classic example is creating a directory and then immediately moving into it.

Bash

mkdir my_new_project && cd my_new_project

This is much safer than running the commands separately. If mkdir fails (perhaps because the directory already exists), the cd command will never even be attempted.

  • The OR Operator: ||

This is the opposite. The command on the right of || will only run if the command on the left fails (returns a non zero exit code). It's perfect for running a fallback action.

Imagine you want to check if a server is online by pinging it. If the ping fails, you want to log an error.

ping -c 1 some_server || echo "The server is unreachable!" > server_error.log

Here, the echo command only runs if the ping command fails.

By mastering variables, conditions, and logical operators, you have elevated your scripting ability. Your programs can now adapt, respond to user input, and handle errors gracefully. They are no longer just simple instruction lists; they are intelligent agents ready to automate your world ! 🎉