Skip to content

12. Shell Scripting Basics

12.1 Your First Script

bash
#!/bin/bash
# This is my first Shell script
# Filename: hello.sh

echo "Hello, Linux World!"
echo "Current time: $(date)"
echo "Current user: $(whoami)"
echo "Hostname: $(hostname)"
bash
# Add execute permission and run the script
chmod +x hello.sh
./hello.sh
bash
$ ./hello.sh
Hello, Linux World!
Current time: Sat Jun 20 10:30:00 CST 2026
Current user: user
Hostname: myserver

12.2 Variables

bash
#!/bin/bash
# Variable examples

# Define variables (no spaces around the equals sign!)
NAME="Linux"
VERSION=6.5
TODAY=$(date +%Y-%m-%d)

# Use variables
echo "System: $NAME"
echo "Version: ${VERSION}"    # Curly braces are optional, used to disambiguate
echo "Date: $TODAY"

# Read-only variable
readonly PI=3.14159

# Delete a variable (read-only variables cannot be deleted)
unset NAME

# Special variables
echo "Script name: $0"
echo "Number of arguments: $#"
echo "All arguments: $@"
echo "Exit status of last command: $?"
echo "Current process PID: $$"

# String operations
STR="Hello World"
echo "Length: ${#STR}"         # 11
echo "Substring: ${STR:0:5}"     # Hello
echo "Replace: ${STR/World/Linux}"  # Hello Linux

12.3 Conditional Statements

bash
#!/bin/bash
# Conditional statement examples

# if-elif-else
AGE=25
if [ $AGE -lt 18 ]; then
    echo "Minor"
elif [ $AGE -ge 18 ] && [ $AGE -lt 60 ]; then
    echo "Adult"
else
    echo "Senior"
fi

# File tests
FILE="/etc/passwd"
if [ -f "$FILE" ]; then
    echo "$FILE is a regular file"
fi
if [ -d "/home/user" ]; then
    echo "Home directory exists"
fi
if [ -r "$FILE" ]; then
    echo "File is readable"
fi
if [ -x "/bin/ls" ]; then
    echo "ls command is executable"
fi

# String comparison
STR="hello"
if [ "$STR" = "hello" ]; then
    echo "Strings are equal"
fi
if [ -z "$EMPTY" ]; then
    echo "Variable is empty"
fi

# More modern syntax (double brackets)
if [[ "$STR" == h* ]]; then
    echo "Starts with h"
fi

# case statement
case "$1" in
    start)
        echo "Starting service"
        ;;
    stop)
        echo "Stopping service"
        ;;
    restart)
        echo "Restarting service"
        ;;
    *)
        echo "Usage: $0 {start|stop|restart}"
        exit 1
        ;;
esac

12.4 Loops

bash
#!/bin/bash
# Loop examples

# for loop — list form
for color in red green blue; do
    echo "Color: $color"
done

# for loop — C-style
for ((i=1; i<=5; i++)); do
    echo "Number: $i"
done

# for loop — iterate over files
for file in /var/log/*.log; do
    echo "Log file: $file"
done

# while loop
COUNT=1
while [ $COUNT -le 5 ]; do
    echo "Count: $COUNT"
    ((COUNT++))
done

# while reading each line of a file
while IFS= read -r line; do
    echo "Line content: $line"
done < /etc/hostname

# until loop (executes while condition is false)
NUM=10
until [ $NUM -le 0 ]; do
    echo -n "$NUM "
    ((NUM--))
done
echo ""

# break and continue
for i in {1..10}; do
    if [ $i -eq 5 ]; then
        continue   # Skip 5
    fi
    if [ $i -eq 8 ]; then
        break      # Stop at 8
    fi
    echo $i
done
bash
$ ./loops.sh
Color: red
Color: green
Color: blue
Number: 1
Number: 2
Number: 3
Number: 4
Number: 5
Count: 1
Count: 2
Count: 3
Count: 4
Count: 5
10 9 8 7 6 5 4 3 2 1
1
2
3
4
6
7

12.5 Functions

bash
#!/bin/bash
# Function examples

# Define a function
greet() {
    local name=$1    # local declares a local variable
    local time=$(date +%H)

    if [ $time -lt 12 ]; then
        echo "Good morning, $name!"
    elif [ $time -lt 18 ]; then
        echo "Good afternoon, $name!"
    else
        echo "Good evening, $name!"
    fi
    return 0
}

# Call the function
greet "Alice"
greet "Bob"

# Function with return value
add() {
    local sum=$(( $1 + $2 ))
    echo $sum    # Return result via echo
}

result=$(add 3 5)
echo "3 + 5 = $result"

# Utility function: check if a command exists
check_command() {
    if ! command -v "$1" &> /dev/null; then
        echo "Error: $1 is not installed"
        return 1
    else
        echo "✓ $1 is installed: $(which $1)"
        return 0
    fi
}

check_command git
check_command docker
check_command nonexistent_cmd
bash
$ ./functions.sh
Good afternoon, Alice!
Good afternoon, Bob!
3 + 5 = 8
 git is installed: /usr/bin/git
 docker is installed: /usr/bin/docker
Error: nonexistent_cmd is not installed

12.6 Practical Script: System Information Report

bash
#!/bin/bash
# sysinfo.sh — System information report script

echo "========================================="
echo "       System Info Report - $(date)"
echo "========================================="
echo ""

echo "--- Host Information ---"
echo "Hostname: $(hostname)"
echo "Kernel version: $(uname -r)"
echo "Operating system: $(cat /etc/os-release | grep PRETTY_NAME | cut -d'"' -f2)"
echo "Uptime: $(uptime -p)"
echo ""

echo "--- CPU Information ---"
echo "Model: $(grep 'model name' /proc/cpuinfo | head -1 | cut -d: -f2 | xargs)"
echo "Cores: $(nproc)"
echo "Load: $(cat /proc/loadavg | awk '{print $1, $2, $3}')"
echo ""

echo "--- Memory Usage ---"
free -h | grep -v Swap
echo ""

echo "--- Disk Usage ---"
df -hT | grep -v tmpfs | grep -v devtmpfs
echo ""

echo "--- Network Interfaces ---"
ip -4 addr show | grep inet | grep -v 127.0.0.1 | awk '{print $2, $NF}'
echo ""

echo "--- Top 5 Processes (Memory) ---"
ps aux --sort=-%mem | awk 'NR<=6 {printf "%-10s %-8s %-6s %s\n", $1, $3"%", $4"%", $11}'
echo ""

echo "========================================="
echo "        Report generation complete"
echo "========================================="
bash
$ chmod +x sysinfo.sh && ./sysinfo.sh
-----------------------------------------
       System Info Report - Sat Jun 20 10:30:00 CST 2026
-----------------------------------------

--- Host Information ---
Hostname: myserver
Kernel version: 5.15.0-91-generic
Operating system: Ubuntu 22.04.3 LTS
Uptime: up 15 hours, 23 minutes

--- CPU Information ---
Model: Intel(R) Core(TM) i7-12700H
Cores: 8
Load: 0.52 0.48 0.35

--- Memory Usage ---
              total        used        free      shared  buff/cache   available
Mem:          3.8Gi       2.7Gi       156Mi       128Mi       999Mi

--- Disk Usage ---
Filesystem     Type      Size  Used Avail Use% Mounted on
/dev/sda1      ext4       50G   22G   26G  46% /
/dev/sda2      ext4      200G  156G   34G  83% /home

--- Network Interfaces ---
192.168.1.100/24 eth0

--- Top 5 Processes (Memory) ---
root       2.3%     12.5%  /usr/sbin/mysqld
www-data   0.5%     8.2%   apache2
root       0.1%     3.1%   /usr/bin/dockerd
user       1.2%     2.8%   vim

-----------------------------------------
        Report generation complete
-----------------------------------------