Skip to main content

Command Palette

Search for a command to run...

Shell Scripts for Beginners: Chapter 1 — Shell Script Introduction

Updated
17 min readView as Markdown

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:

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:

vi setup_smarthome.sh

Inside this file, type the following:

#!/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:

#!/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 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:

ls -l setup_smarthome.sh

You'll see something like:

-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:

chmod +x setup_smarthome.sh

Now run it:

./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:

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:

setup_smarthome.sh

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

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:

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 $:

echo $device_name

Or inside a string:

echo "Setting up device: $device_name"

Updated Script Using Variables

#!/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:

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_Namedevice_name
Use lowercase with underscores (best practice) living_room_status

Good variable names:

device_name=thermostat
room_id=bedroom

Bad variable names:

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?

./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:

./setup_smarthome.sh bedroom_thermostat

Inside the script:

  • $0 = ./setup_smarthome.sh

  • $1 = bedroom_thermostat

Updated Script With Command Line Arguments

#!/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:

./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:

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

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

#!/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:

#!/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:

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:

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

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

Output:

Total devices: 9

Method 2 — Double Parentheses (( ))

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

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

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:

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:

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

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

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

active_devices=7
total_devices=10

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

Output:

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:

#!/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.