# Bash Scripting Fundamentals: Commands, Variables, Loops, and Automation

* * *

Bash scripting allows you to automate repetitive tasks in Linux by combining commands into scripts that execute in sequence. Instead of repeatedly typing the same commands into a terminal, you can save them in a file and execute them whenever needed.

This is useful for everyday Linux administration, file management, system checks, and scheduled tasks.

This guide covers the fundamentals of Bash scripting, from creating your first script to working with loops, processing files, debugging, and scheduling automated tasks.

## 1\. What Is a Bash Script?

A Bash script is a text file containing commands that the Bash shell can interpret and execute.

For example, instead of typing several commands individually, you can save them in a script and execute them together.

Create a file called `hello.sh`:

```bash
#!/bin/bash

echo "Hello, World!"
echo "Today is $(date)"
```

Let's break this down.

*   `#!/bin/bash` — The shebang identifies the interpreter to use when the script is executed directly.
    
*   `echo` — Prints text to standard output.
    
*   `$(date)` — Runs the `date` command and substitutes its output into the surrounding command.
    

To make the script executable, run:

```bash
chmod u+x hello.sh
```

Then execute it:

```bash
./hello.sh
```

The terminal will display the messages and the current date.

**Why use scripts?**

Scripts reduce repetitive work, make tasks easier to reproduce, and provide a foundation for automating system administration.

## 2\. Variables and User Input

Variables allow scripts to store and reuse values.

Consider this example:

```bash
#!/bin/bash

name="Wale"

echo "My name is $name"
```

Here, `name` is a variable containing the value `Wale`.

The `$name` expression retrieves that value.

Notice that there are no spaces around the `=` when assigning a value in Bash:

```bash
name="Wale"
```

This is different from:

```bash
name = "Wale"
```

The second example is not a valid variable assignment in Bash.

### Accepting user input

The `read` command allows a script to receive input from the user.

```bash
#!/bin/bash

echo "What is your name?"

read -r name

echo "Hello, $name!"
```

When executed, the script waits for the user to enter a name and press Enter.

The entered value is stored in the `name` variable and displayed in the final message.

The `-r` option prevents `read` from treating backslashes as escape characters.

### Passing arguments to a script

You can also supply values when executing a script.

Consider `greeting.sh`:

```bash
#!/bin/bash

echo "My name is $1"
```

Execute it with:

```bash
./greeting.sh Wale
```

Output:

```text
My name is Wale
```

Here, `$1` represents the first positional argument passed to the script.

For example:

*   `$1` — First argument.
    
*   `$2` — Second argument.
    
*   `$3` — Third argument.
    

This allows scripts to accept different values without requiring interactive input.

## 3\. Working with Files and Command Output

Linux commands can read from files and redirect their output into files.

Understanding these operations is essential for writing useful scripts.

### Redirecting output

The `>` operator redirects command output into a file.

```bash
ls > output.txt
```

This writes the directory listing to `output.txt`.

**Important:** If the file already exists, `>` overwrites its contents.

To append output instead, use `>>`:

```bash
echo "Another entry" >> output.txt
```

This adds the new text to the end of the file without replacing the existing contents.

### Reading file contents

The `cat` command displays a file's contents:

```bash
cat output.txt
```

By contrast:

```bash
ls output.txt
```

lists the file itself rather than displaying its contents.

### Reading input from a file

The `<` operator redirects a file's contents into a command's standard input.

For example:

```bash
while IFS= read -r line
do
    echo "$line"
done < output.txt
```

This reads `output.txt` one line at a time and prints each line.

The expression:

```bash
done < output.txt
```

redirects the loop's standard input from the file.

This pattern is useful when processing text files line by line.

## 4\. Understanding Loops

Loops allow a script to repeat commands without requiring you to write the same instructions multiple times.

Bash supports several types of loops, including `while` and `for`.

### The `while` loop

A `while` loop continues executing as long as its condition is true.

```bash
#!/bin/bash

i=1

while [[ $i -le 5 ]]
do
    echo "$i"
    ((i += 1))
done
```

Output:

```text
1
2
3
4
5
```

How it works:

1.  `i=1` initializes the variable.
    
2.  `[[ $i -le 5 ]]` checks whether `i` is less than or equal to 5.
    
3.  `do` marks the beginning of the commands to execute.
    
4.  `echo "$i"` prints the current value.
    
5.  `((i += 1))` increments the variable by one.
    
6.  `done` marks the end of the loop.
    

When `i` becomes 6, the condition is false and the loop stops.

**Watch out:** If the variable never changes in a way that makes the condition false, the loop may run indefinitely.

### The `for` loop

A `for` loop is useful when iterating over a known sequence of values.

```bash
#!/bin/bash

for i in {1..5}
do
    echo "$i"
done
```

Output:

```text
1
2
3
4
5
```

Here, `{1..5}` expands into the sequence of numbers from 1 to 5.

The loop assigns each value to `i` and executes the commands inside the loop.

Unlike the previous example, you don't need to increment the variable manually.

## 5\. Using `case` for Multiple Conditions

The `case` statement allows a script to compare a value against several patterns and execute the commands associated with the first matching pattern.

For example:

```bash
#!/bin/bash

fruit="apple"

case "$fruit" in
    apple)
        echo "This is an apple."
        ;;
    orange)
        echo "This is an orange."
        ;;
    *)
        echo "This fruit is not recognized."
        ;;
esac
```

Output:

```text
This is an apple.
```

Here's what the syntax means:

*   `case "$fruit" in` — Begins the comparison.
    
*   `apple)` — Matches the value `apple`.
    
*   `;;` — Ends that case and exits the `case` statement.
    
*   `*)` — Acts as the default pattern when no earlier pattern matches.
    
*   `esac` — Marks the end of the statement.
    

The `case` statement is useful when a script needs to respond differently to multiple possible inputs.

For example, it can process user choices, command-line options, or service names.

## 6\. Debugging Bash Scripts

A script may fail because of incorrect syntax, unexpected input, or incorrect assumptions about how a command behaves.

Bash provides tools to help identify these problems.

### Using `set -x`

Add this line near the beginning of your script:

```bash
#!/bin/bash
set -x
```

Bash will print commands and their expanded arguments to standard error as it executes them.

For example:

```bash
#!/bin/bash
set -x

name="Wale"
echo "Hello, $name"
```

The trace helps you see how Bash interprets and executes the commands.

You can also enable tracing for a particular section:

```bash
set -x

# Commands to investigate

set +x
```

The first command enables tracing, while the second disables it.

This is useful when you want to investigate a specific part of a script rather than trace every command.

**Security note:** Be careful when debugging scripts that handle passwords, access tokens, or other secrets. Tracing can expose sensitive values in terminal output or logs.

## 7\. Scheduling Scripts with Cron

Some tasks need to run automatically at particular times.

For example, you might want a script to run every morning, periodically check a service, or perform a routine maintenance task.

On Linux systems that use cron, scheduled jobs can be managed with `crontab`.

### Viewing scheduled jobs

Run:

```bash
crontab -l
```

This displays the current user's scheduled cron jobs.

To edit them, run:

```bash
crontab -e
```

### Understanding cron syntax

A standard cron expression contains five fields:

```text
* * * * *
│ │ │ │ │
│ │ │ │ └── Day of the week
│ │ │ └──── Month
│ │ └────── Day of the month
│ └──────── Hour
└────────── Minute
```

Each field controls when the scheduled command runs.

### Example 1: Run a script every day at midnight

```cron
0 0 * * * /path/to/script.sh
```

The five fields specify minute 0, hour 0, and every day, month, and weekday.

The script runs at midnight each day, according to the cron daemon's time settings.

### Example 2: Run a script every five minutes

```cron
*/5 * * * * /path/to/script.sh
```

The `*/5` expression means every five minutes.

**Practical consideration:** When scheduling scripts, use appropriate file permissions and valid paths. Cron jobs may also need explicit environment variables or logging because they don't necessarily run with the same environment as your interactive terminal.

* * *

## Conclusion

Bash scripting provides a practical way to automate tasks in Linux.

The fundamentals covered here—variables, user input, positional arguments, file redirection, loops, conditional selection, debugging, and scheduling—form a foundation for more advanced automation.

As scripts become more complex, these concepts can be combined to perform repetitive administrative tasks, process files, and support infrastructure operations.

The key is to understand what each command does, how the pieces fit together, and how to verify that a script behaves as expected.

## References

*   [GNU Bash Reference Manual](https://www.gnu.org/software/bash/manual/bash.html)
    
*   [Bash Builtins: `read`](https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html)
    
*   [Bash Debugging with `set -x`](https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html)
