# Shell Scripts for Beginners: Chapter 1 — Shell Script Introduction

> **Series:** Shell Scripts for Beginners **Chapter:** Shell Script Introduction **Topics Covered:** Course Introduction · Project Introduction · Creating Your First Shell Script · Variables · Command Line Arguments · Read Inputs · Arithmetic Operations

* * *

## Welcome — What This Blog Is About

If you've ever found yourself typing the same Linux commands over and over again — backing up files, checking system health, restarting services — you've already felt the pain that shell scripting solves. This blog is the written companion to Chapter 1 of the *Shell Scripts for Beginners* course. It walks you through everything from "what even is a shell script?" all the way to doing math inside your scripts.

No programming experience required. Seriously. If you can open a terminal and type `ls`, you're ready.

We'll be learning through a fun, real-world project: **automating a Smart Home Control System** using shell scripts. Think of it as building the brain of a smart home — turning devices on and off, checking their status, and running sequences of commands automatically. Let's dive in.

* * *

## 1\. Course Introduction — Why Shell Scripting?

### What Is a Shell Script?

A **shell script** is simply a text file containing a sequence of Linux commands that are executed one after another. Instead of typing ten commands manually every time, you write them once in a file, and the shell (the command-line interpreter) runs them all for you automatically.

Think of it like a recipe. A chef doesn't reinvent bread every morning — they follow a recipe. Shell scripts are your recipes for the terminal.

### Why Should You Learn Shell Scripting?

Shell scripting is one of those foundational skills that pays dividends every single day for anyone working with computers, especially system administrators and DevOps engineers. Here's what it can help you do:

*   **Automate repetitive tasks** — daily backups, log rotation, system cleanup
    
*   **Manage multiple servers** — install packages or apply patches across dozens of machines simultaneously
    
*   **Monitor your system** — periodically check memory, CPU, and disk usage, and raise alerts when thresholds are crossed
    
*   **Perform audits** — identify logged-in users, track resource-hungry processes, review activity logs
    
*   **Troubleshoot faster** — search across multiple log files at once to pinpoint root causes
    

### Who Is This For?

This course (and this blog) is designed for:

*   Absolute beginners with zero programming experience
    
*   System administrators and IT engineers looking to automate their workflows
    
*   Anyone curious about Linux automation
    

**Prerequisite:** Basic Linux command-line experience (knowing commands like `ls`, `mkdir`, `cd`) is all you need.

* * *

## 2\. Project Introduction — The Smart Home Control System

To make learning concrete and fun, we'll build our scripts around a **Smart Home Automation** project.

### The Scenario

You're the lead engineer for a Smart Home Control System. Your job is to automate the sequence of operations that power on, configure, and monitor various smart home devices — lights, thermostats, security cameras, and door locks.

Every morning, your home needs to:

1.  Power on the central hub
    
2.  Connect all devices to the home network
    
3.  Run a system check on all devices
    
4.  Activate the daily automation schedule
    
5.  Confirm everything is running correctly
    

Doing this manually every day? Tedious. Letting a shell script do it? Elegant.

### The Commands at Your Disposal

Just like Linux gives you commands such as `ls`, `mkdir`, and `useradd`, our Smart Home system comes with its own set of commands:

| Task | Command |
| --- | --- |
| Power on the hub | `smarthome start hub` |
| Connect devices to network | `smarthome connect network` |
| Run device health check | `smarthome check devices` |
| Activate daily schedule | `smarthome activate schedule` |
| Verify system status | `smarthome status` |
| List all devices | `smarthome list` |
| Add a new device | `smarthome add <device-name>` |
| Remove a device | `smarthome delete <device-name>` |
| Debug a failing device | `smarthome debug <device-name>` |

Don't worry about memorizing these — we'll use them step by step as we build our scripts.

* * *

## 3\. Creating Your First Shell Script

### Step 1 — Plan Before You Type

Before writing a single line of code, always write down the exact steps and commands your script needs to execute. This is a habit that separates good scripters from frustrated ones.

For our Smart Home morning startup routine, the steps are:

```plaintext
1. Create a folder for today's automation session
2. Add the living room lights device
3. Power on the hub
4. Connect all devices to the network
5. Run a device health check
6. Activate the daily schedule
7. Check and display the system status
```

### Step 2 — Write the Script

Open a terminal and create a new file:

```bash
vi setup_smarthome.sh
```

Inside this file, type the following:

```bash
#!/bin/bash
# Smart Home Morning Startup Script

mkdir living_room_session
smarthome add living_room_lights

smarthome start hub
smarthome connect network
smarthome check devices
smarthome activate schedule

smarthome_status=$(smarthome status)
echo "System Status: $smarthome_status"
```

### The Shebang Line — `#!/bin/bash`

The very first line of every shell script should be:

```bash
#!/bin/bash
```

This is called the **shebang** (pronounced "shuh-bang"). It tells the operating system: *"Use the Bash shell to execute this file."* Without it, the system might not know how to run your script. Always include it.

### Step 3 — Make the Script Executable

After creating the file, you can't run it yet. Try it:

```bash
bash setup_smarthome.sh
```

Wait — why can't we just type `setup_smarthome.sh` directly? Because the operating system only recognizes files as executable commands when:

1.  The **execute permission bit** is set on the file
    
2.  The directory containing the script is listed in the `PATH` environment variable
    

### Setting Execute Permission

Check the current permissions:

```bash
ls -l setup_smarthome.sh
```

You'll see something like:

```plaintext
-rw-r--r-- 1 user user 245 Apr 1 10:00 setup_smarthome.sh
```

Notice there's no `x` (execute) bit. Add it using `chmod`:

```bash
chmod +x setup_smarthome.sh
```

Now run it:

```bash
./setup_smarthome.sh
```

### Adding to the PATH

If you want to run your script from *anywhere* without typing the full path, add its directory to the `PATH` variable:

```bash
export PATH=$PATH:/home/youruser
```

Using `$PATH` instead of typing the full existing path is important — it **appends** your directory to whatever already exists, rather than replacing it (which would break all your other commands).

Now you can run:

```bash
setup_smarthome.sh
```

From any directory. You can also verify where the script is located:

```bash
which setup_smarthome.sh
```

### Best Practices for Naming Scripts

| ❌ Bad Name | ✅ Good Name |
| --- | --- |
| `script1.sh` | `setup_smarthome.sh` |
| `my_script.sh` | `morning_startup.sh` |
| `test.sh` | `check_device_health.sh` |

Name your scripts so that a stranger instantly understands what they do. If you plan to use the script as a runnable command, you can drop the `.sh` extension. If it's more of an internal utility, keep it.

* * *

## 4\. Variables — Stop Hardcoding Values

### The Problem With Hardcoding

Look at our script — the name `living_room_lights` appears in multiple places. What if tomorrow we want to run the same startup routine for `bedroom_lights`? We'd have to hunt through every line and change every occurrence. Miss one, and the script breaks in unexpected ways.

This is what we call **hardcoding** — baking a specific value directly into the code — and it's bad practice.

### What Is a Variable?

A **variable** is a named container that holds a value. Instead of writing `living_room_lights` everywhere, you write the name once, store it in a variable, and reference the variable everywhere else.

### Declaring and Using Variables

Here's how to define a variable:

```bash
device_name=living_room_lights
```

> ⚠️ **No spaces around the** `=` **sign.** `device_name = living_room_lights` will cause an error.

To **use** (or "expand") a variable, prefix it with `$`:

```bash
echo $device_name
```

Or inside a string:

```bash
echo "Setting up device: $device_name"
```

### Updated Script Using Variables

```bash
#!/bin/bash
# Smart Home Morning Startup Script

device_name=living_room_lights

mkdir ${device_name}_session
smarthome add $device_name

smarthome start hub
smarthome connect network
smarthome check devices
smarthome activate schedule

system_status=$(smarthome status)
echo "System Status for $device_name: $system_status"
```

Now to run the same script for `bedroom_thermostat`, you only change **one line** at the top. Everything else stays the same.

### Storing Command Output in a Variable

Notice this line:

```bash
system_status=$(smarthome status)
```

The `$(...)` syntax is called **command substitution**. It runs the command inside and stores whatever it prints into the variable. This is extremely powerful — you can capture any command's output and use it later.

### Variable Naming Rules

| Rule | Example |
| --- | --- |
| Only letters, numbers, and underscores | `device_name` ✅ |
| No hyphens | `device-name` ❌ |
| Case-sensitive | `Device_Name` ≠ `device_name` |
| Use lowercase with underscores (best practice) | `living_room_status` ✅ |

**Good variable names:**

```bash
device_name=thermostat
room_id=bedroom
```

**Bad variable names:**

```bash
DeviceName=thermostat     # avoid CamelCase
device-name=thermostat    # hyphens not allowed
d=thermostat              # too cryptic
```

* * *

## 5\. Command Line Arguments — Making Scripts Flexible

### The Problem We're Solving

Even with variables, our script still requires you to **edit the file** every time you want to run it for a different device. That's still inconvenient.

Wouldn't it be much better to do this?

```bash
./setup_smarthome.sh bedroom_thermostat
```

And the script automatically knows the device name is `bedroom_thermostat` — without you ever opening the file? That's exactly what **command line arguments** enable.

### How Arguments Work

When you run a script, everything you type after the script name is broken into numbered **positional parameters**:

| What You Type | Variable Inside Script |
| --- | --- |
| The script name itself | `$0` |
| First argument | `$1` |
| Second argument | `$2` |
| Third argument | `$3` |
| ... and so on | `$4`, `$5`, ... |

For example, running:

```bash
./setup_smarthome.sh bedroom_thermostat
```

Inside the script:

*   `$0` = `./setup_smarthome.sh`
    
*   `$1` = `bedroom_thermostat`
    

### Updated Script With Command Line Arguments

```bash
#!/bin/bash
# Smart Home Morning Startup Script

device_name=$1

mkdir ${device_name}_session
smarthome add $device_name

smarthome start hub
smarthome connect network
smarthome check devices
smarthome activate schedule

system_status=$(smarthome status)
echo "System Status for $device_name: $system_status"
```

Now you can run:

```bash
./setup_smarthome.sh living_room_lights
./setup_smarthome.sh bedroom_thermostat
./setup_smarthome.sh front_door_camera
```

Each run uses a different device — **the script itself never changes.**

### Why Not Just Use `$1` Directly?

You *could* replace `device_name=$1` and just use `$1` throughout the script:

```bash
mkdir ${1}_session
smarthome add $1
echo "Status for $1: $system_status"
```

This works, but it's harder to read. Six months later, when you or a teammate opens this script, `$1` is meaningless. `$device_name` tells you exactly what it represents.

**Best practice:** Assign `$1`, `$2`, etc. to descriptively named variables at the top of your script, then use those variables throughout.

### Design Your Scripts to Be Reusable

> *"Always develop the script keeping in mind that it is to be reused by another person who has not developed the script — or probably doesn't even have experience working with shell scripts."*

A reusable script:

*   Takes inputs via command line arguments (not hardcoded values)
    
*   Has meaningful variable names
    
*   Requires zero modification before each run
    

* * *

## 6\. Read Inputs — Interactive Prompts

### Another Way to Get Input

Command line arguments are great for automation. But sometimes you want your script to **ask the user a question** while it's running — like a wizard or setup tool.

The `read` command lets you do exactly that.

### Basic Syntax

```bash
read variable_name
```

When the script hits this line, it **pauses and waits** for the user to type something. Whatever they type gets stored in `variable_name`.

### Example

```bash
#!/bin/bash
read device_name
smarthome add $device_name
echo "Device $device_name has been added."
```

This works, but there's a problem: when the script pauses, the terminal just shows a blinking cursor. The user has no idea what they're supposed to type.

### Adding a Prompt Message

Use the `-p` flag to display a message before waiting for input:

```bash
#!/bin/bash
read -p "Enter the device name to set up: " device_name
smarthome add $device_name
echo "Device $device_name has been set up successfully."
```

Now the user sees:

```plaintext
Enter the device name to set up: _
```

Much friendlier.

### When to Use `read` vs. Command Line Arguments

This is a common question, and the answer depends on how your script will be used:

| Situation | Recommended Approach |
| --- | --- |
| Script will be run manually by a person | `read` with a prompt is fine |
| Script needs confirmation before a destructive action | `read` (e.g., "Are you sure you want to delete this device? \[y/n\]") |
| Script will be called by another script (automation) | Command line arguments — `read` would freeze the automation |
| Menu-driven interactive programs | `read` |
| Scripts that will run on a schedule (cron jobs) | Command line arguments — no human available to answer prompts |

### The Best of Both Worlds

Ideally, a well-designed script checks whether a command line argument was provided. If yes, it uses that. If not, it prompts the user. We'll cover the conditional logic needed for this when we get to `if` statements in a later chapter.

* * *

## 7\. Arithmetic Operations — Doing Math in Shell Scripts

### Why Arithmetic in Shell Scripts?

You might want to count devices, calculate percentage usage, track elapsed time, or compute threshold values. Shell scripting supports math — though with a few quirks to be aware of.

### Method 1 — The `expr` Command

`expr` is a basic utility for evaluating expressions:

```bash
expr 6 + 3       # Output: 9
expr 10 - 4      # Output: 6
expr 8 / 2       # Output: 4
expr 5 \* 3      # Output: 15
```

> ⚠️ **Important rules for** `expr`**:**
> 
> *   Operators and numbers **must** be separated by spaces. `expr 6+3` will **not** work.
>     
> *   For multiplication, you **must** escape the with a backslash: `\*`. This is because is a wildcard character in the shell.
>     

### Using Variables with `expr`

```bash
device_count=6
new_devices=3
total=$(expr $device_count + $new_devices)
echo "Total devices: $total"
```

Output:

```plaintext
Total devices: 9
```

### Method 2 — Double Parentheses `(( ))`

The double-parentheses syntax is more modern and much more intuitive:

```bash
echo $((6 + 3))       # 9
echo $((10 - 4))      # 6
echo $((8 / 2))       # 4
echo $((5 * 3))       # 15
```

**Advantages over** `expr`**:**

*   No need to escape for multiplication
    
*   Spaces between operator and values are optional
    
*   Variables inside don't need the `$` prefix
    
*   Feels more like "normal" programming math
    

### Example With Variables

```bash
a=6
b=3

echo $((a + b))    # 9
echo $((a * b))    # 18
echo $((a - b))    # 3
```

### C-Style Increment and Decrement

You can also use the familiar `++` and `--` operators:

```bash
device_count=5
((device_count++))
echo $device_count    # 6

((device_count--))
echo $device_count    # 5
```

> ℹ️ Note: `++a` and `--a` work the same way as in C — the value is updated and then used.

### Method 3 — The `bc` Utility (Floating Point Math)

Both `expr` and `$(( ))` have a significant limitation: they only work with **whole numbers (integers)**. Division always gets truncated:

```bash
echo $((10 / 3))    # Output: 3 (not 3.333...)
```

For decimal results, use the `bc` utility (Basic Calculator):

```bash
echo "10 / 3" | bc -l    # Output: 3.33333333333333333333
```

The `-l` flag tells `bc` to use its math library, which enables floating-point output.

### Practical Example — Calculating Device Load Percentage

```bash
active_devices=7
total_devices=10

load_percentage=$(echo "scale=2; ($active_devices / $total_devices) * 100" | bc -l)
echo "Current load: $load_percentage%"
```

Output:

```plaintext
Current load: 70.00%
```

`scale=2` tells `bc` to give you 2 decimal places.

### Arithmetic Methods — Quick Comparison

| Feature | `expr` | `$(( ))` | `bc` |
| --- | --- | --- | --- |
| Basic math | ✅ | ✅ | ✅ |
| Needs spaces | ✅ Required | ❌ Optional | ❌ |
| Multiplication | `\*` (escape needed) | `*` (no escape) | `*` |
| Floating point | ❌ | ❌ | ✅ |
| Variables (inside) | `$var` | `var` (no `$` needed) | `$var` |

* * *

## Putting It All Together — Our Smart Home Script

Here's a final version of our script incorporating everything we've learned in this chapter:

```bash
#!/bin/bash
# Smart Home Morning Startup Script
# Usage: ./setup_smarthome.sh <device_name>

# Get device name from command line argument, or prompt if not provided
device_name=$1

if [ -z "$device_name" ]; then
    read -p "Enter the device name to set up: " device_name
fi

# Track session
session_dir="${device_name}_session"
mkdir $session_dir

# Add the device
smarthome add $device_name

# Run the startup sequence
smarthome start hub
smarthome connect network
smarthome check devices
smarthome activate schedule

# Capture and display status
system_status=$(smarthome status)
echo "System Status for $device_name: $system_status"

# Arithmetic — count total devices
total_devices=$(smarthome list | wc -l)
echo "Total devices managed: $total_devices"
```

This script:

*   Accepts a device name as a command line argument
    
*   Falls back to prompting the user if none is provided
    
*   Uses meaningful variable names throughout
    
*   Captures command output into variables
    
*   Displays a running device count
    

* * *

## Chapter 1 Summary

Here's a quick recap of everything covered:

| Topic | Key Takeaway |
| --- | --- |
| **What Shell Scripts Are** | Text files of Linux commands, executed automatically by the shell |
| **Creating a Script** | Use any text editor; always start with `#!/bin/bash` |
| **Making It Executable** | `chmod +x scriptname.sh`; add directory to `$PATH` to run it like a command |
| **Variables** | Store values with `name=value`; use them with `$name`; capture command output with `$(command)` |
| **Command Line Arguments** | Access via `$1`, `$2`, etc.; assign to named variables for readability |
| **Read Inputs** | Use `read -p "prompt" variable` for interactive user input |
| **Arithmetic** | Use `expr` or `$(( ))` for integers; use `bc -l` for decimals |

* * *

## What's Next?

In the next chapter, we'll explore **Control Flow** — making your scripts smart enough to make decisions. We'll cover `if/else` statements, comparison operators, and loops (`for` and `while`). This is where scripting really starts to feel like programming.

Until then, practice the concepts from this chapter. Try building a small script that automates something repetitive on your own system. Even something simple — like creating a folder structure or checking disk usage — is a fantastic start.

Happy scripting! 🖥️

* * *

*This blog is part of the* ***Shell Scripts for Beginners*** *series. Each post corresponds to a chapter of the course, with hands-on examples designed to take you from zero to confident scripter.*
