Skip to content

Shell Scripting Basics

What is a Shell Script?

A shell script is a text file containing a series of commands that is interpreted and executed by a Shell. It can automate repetitive tasks, batch process files, manage systems, and more.

Creating Your First Script

Writing the Script

bash
#!/bin/bash
# My first script
# Author: Maxwell
# Date: 2025-01-09

echo "Hello, World!"
echo "Current time: $(date)"
echo "Current user: $USER"
echo "Current directory: $PWD"

Shebang

The #! at the beginning of the script is called the Shebang, which specifies the interpreter:

bash
#!/bin/bash          # Use bash
#!/bin/sh            # Use sh
#!/usr/bin/env bash  # Recommended, uses bash from environment
#!/usr/bin/env python3  # Python script

Running the Script

bash
# Method 1: Add execute permission
$ chmod +x script.sh
$ ./script.sh

# Method 2: Run with bash
$ bash script.sh

# Method 3: Use source (execute in current shell)
$ source script.sh
$ . script.sh

Variables

Defining and Using Variables

bash
#!/bin/bash

# Define variables (no spaces around =)
name="Maxwell"
age=25
path="/home/maxwell"

# Use variables
echo "Name: $name"
echo "Age: ${age}"
echo "Path: ${path}/documents"

# Read-only variables
readonly PI=3.14159

# Delete variable
unset age

Variable Types

bash
# String
str="Hello World"

# Number (actually all are strings)
num=42

# Array
arr=(one two three)
echo ${arr[0]}    # one
echo ${arr[@]}    # all elements
echo ${#arr[@]}   # array length

Special Variables

VariableDescription
$0Script name
$1-$9Positional parameters
${10}10th and subsequent parameters
$#Number of parameters
$@All parameters (as independent strings)
$*All parameters (as single string)
$?Exit status of previous command
$$PID of current script
$!PID of last background process
bash
#!/bin/bash
echo "Script name: $0"
echo "First parameter: $1"
echo "Second parameter: $2"
echo "Parameter count: $#"
echo "All parameters: $@"

String Operations

bash
str="Hello World"

# Length
echo ${#str}         # 11

# Substring
echo ${str:0:5}      # Hello
echo ${str:6}        # World

# Replacement
echo ${str/World/Bash}    # Hello Bash
echo ${str//o/O}          # HellO WOrld (all replacement)

# Deletion
filename="document.txt.bak"
echo ${filename%.bak}     # document.txt (delete from right)
echo ${filename%%.*}      # document (greedy)
echo ${filename#*.}       # txt.bak (delete from left)
echo ${filename##*.}      # bak (greedy)

# Default value
echo ${undefined:-default}    # Use default if variable is undefined
echo ${undefined:=default}    # Set default if variable is undefined
echo ${undefined:?error msg}  # Error if undefined

Quotes

Single Quotes

Content inside single quotes is output literally, variables are not expanded:

bash
name="Maxwell"
echo 'Hello $name'    # Hello $name

Double Quotes

Variables and command substitution are expanded inside double quotes:

bash
name="Maxwell"
echo "Hello $name"    # Hello Maxwell
echo "Today is $(date +%Y-%m-%d)"

Backticks and $()

Command substitution:

bash
# Backticks (old syntax)
today=`date +%Y-%m-%d`

# $() (recommended)
today=$(date +%Y-%m-%d)
files=$(ls -la)

Arithmetic Operations

$(()) Syntax

bash
a=10
b=3

echo $((a + b))    # 13
echo $((a - b))    # 7
echo $((a * b))    # 30
echo $((a / b))    # 3
echo $((a % b))    # 1
echo $((a ** b))   # 1000 (power operation)

# Increment/decrement
((a++))
((b--))
((a += 5))

let Command

bash
let "a = 10 + 5"
let "a++"

expr Command

bash
result=$(expr 10 + 5)
result=$(expr 10 \* 5)  # Multiplication needs escaping

bc Calculator (Floating Point)

bash
# Integer division
echo $((10 / 3))    # 3

# Floating-point division
echo "scale=2; 10 / 3" | bc    # 3.33

# Complex calculations
result=$(echo "scale=4; sqrt(2)" | bc)

Conditional Statements

if Statement

bash
#!/bin/bash

if [ condition ]; then
    command
fi

if [ condition ]; then
    command1
else
    command2
fi

if [ condition1 ]; then
    command1
elif [ condition2 ]; then
    command2
else
    command3
fi

Conditional Expressions

File Tests

ExpressionDescription
-e fileFile exists
-f fileIs regular file
-d fileIs directory
-r fileIs readable
-w fileIs writable
-x fileIs executable
-s fileFile is not empty
-L fileIs symbolic link
bash
if [ -f "/etc/passwd" ]; then
    echo "File exists"
fi

if [ -d "/home" ]; then
    echo "Directory exists"
fi

String Tests

ExpressionDescription
-z strString is empty
-n strString is not empty
str1 = str2Strings are equal
str1 != str2Strings are not equal
bash
name="Maxwell"
if [ -n "$name" ]; then
    echo "Name is not empty"
fi

if [ "$name" = "Maxwell" ]; then
    echo "Name matches"
fi

Numeric Comparisons

ExpressionDescription
n1 -eq n2Equal
n1 -ne n2Not equal
n1 -gt n2Greater than
n1 -ge n2Greater or equal
n1 -lt n2Less than
n1 -le n2Less or equal
bash
age=25
if [ $age -ge 18 ]; then
    echo "Adult"
fi

Logical Operations

bash
# AND
if [ condition1 ] && [ condition2 ]; then
if [ condition1 -a condition2 ]; then

# OR
if [ condition1 ] || [ condition2 ]; then
if [ condition1 -o condition2 ]; then

# NOT
if [ ! condition ]; then

[[ ]] Extended Test

[[ ]] is a Bash extension with more powerful features:

bash
# Support regex matching
if [[ "$str" =~ ^[0-9]+$ ]]; then
    echo "Is a number"
fi

# Support pattern matching
if [[ "$file" == *.txt ]]; then
    echo "Is a text file"
fi

# Safer string comparison
if [[ "$name" == "Maxwell" ]]; then
    echo "Matches"
fi

case Statement

bash
#!/bin/bash

case $1 in
    start)
        echo "Start service"
        ;;
    stop)
        echo "Stop service"
        ;;
    restart)
        echo "Restart service"
        ;;
    *)
        echo "Usage: $0 {start|stop|restart}"
        exit 1
        ;;
esac

Loops

for Loop

bash
# List loop
for item in item1 item2 item3; do
    echo $item
done

# Array loop
arr=(one two three)
for item in ${arr[@]}; do
    echo $item
done

# File loop
for file in *.txt; do
    echo "Processing: $file"
done

# Range loop
for i in {1..5}; do
    echo $i
done

# C-style loop
for ((i=0; i<5; i++)); do
    echo $i
done

# Command output loop
for user in $(cat /etc/passwd | cut -d: -f1); do
    echo "User: $user"
done

while Loop

bash
#!/bin/bash

count=0
while [ $count -lt 5 ]; do
    echo "Count: $count"
    ((count++))
done

# Read file
while IFS= read -r line; do
    echo "Line: $line"
done < file.txt

# Infinite loop
while true; do
    echo "Running..."
    sleep 1
done

until Loop

bash
count=0
until [ $count -ge 5 ]; do
    echo "Count: $count"
    ((count++))
done

Loop Control

bash
# break - exit loop
for i in {1..10}; do
    if [ $i -eq 5 ]; then
        break
    fi
    echo $i
done

# continue - skip current iteration
for i in {1..5}; do
    if [ $i -eq 3 ]; then
        continue
    fi
    echo $i
done

Functions

Defining and Calling

bash
#!/bin/bash

# Define function
function greet() {
    echo "Hello, $1!"
}

# Or (POSIX compatible)
greet() {
    echo "Hello, $1!"
}

# Call function
greet "Maxwell"
greet "World"

Function Parameters and Return Values

bash
#!/bin/bash

add() {
    local a=$1
    local b=$2
    local sum=$((a + b))
    echo $sum    # Return value via echo
}

# Get return value
result=$(add 3 5)
echo "Result: $result"

# Use return (can only return 0-255)
check_file() {
    if [ -f "$1" ]; then
        return 0
    else
        return 1
    fi
}

if check_file "/etc/passwd"; then
    echo "File exists"
fi

Local Variables

bash
#!/bin/bash

global_var="global"

my_function() {
    local local_var="local"
    global_var="Modified in function"
    echo "Inside function: $local_var, $global_var"
}

my_function
echo "Outside function: $global_var"
echo "Outside function: $local_var"     # Empty (local variable not visible)

Input/Output

Reading User Input

bash
#!/bin/bash

# Basic read
echo -n "Please enter name: "
read name
echo "Hello, $name"

# With prompt
read -p "Please enter age: " age

# Hide input (password)
read -sp "Please enter password: " password
echo

# Set timeout
read -t 5 -p "Enter within 5 seconds: " answer

# Read into array
read -a arr -p "Enter multiple values: "
echo "First: ${arr[0]}"

Output

bash
# echo
echo "Normal output"
echo -n "No newline"
echo -e "Support\ttab\newline\ncharacters"

# printf (formatted output)
printf "Name: %s, Age: %d\n" "Maxwell" 25
printf "%-10s %5d\n" "Item" 100

Practical Examples

Backup Script

bash
#!/bin/bash

BACKUP_DIR="/backup"
SOURCE_DIR="/var/www"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/www_${DATE}.tar.gz"

# Create backup directory
mkdir -p "$BACKUP_DIR"

# Create backup
tar -czf "$BACKUP_FILE" "$SOURCE_DIR"

if [ $? -eq 0 ]; then
    echo "Backup successful: $BACKUP_FILE"
else
    echo "Backup failed"
    exit 1
fi

# Delete backups 7 days old
find "$BACKUP_DIR" -name "www_*.tar.gz" -mtime +7 -delete

System Monitoring Script

bash
#!/bin/bash

echo "=== System Information ==="
echo "Hostname: $(hostname)"
echo "System: $(uname -s)"
echo "Kernel: $(uname -r)"
echo

echo "=== CPU Usage ==="
top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d% -f1
echo

echo "=== Memory Usage ==="
free -h | grep Mem
echo

echo "=== Disk Usage ==="
df -h | grep -v tmpfs

Summary

This chapter introduced shell scripting basics:

  • Script structure: Shebang, comments, execution
  • Variables: Definition, usage, special variables
  • Operations: Arithmetic, string operations
  • Conditionals: if, case, test expressions
  • Loops: for, while, until
  • Functions: Definition, parameters, return values
  • Input/Output: read, echo, printf

Shell scripting is the foundation of Linux automation. Mastering it will greatly improve your work efficiency.


Previous chapter: SSH Remote Connection

Next chapter: Environment Variables

Content is for learning and research only.