15%

Save 15% on All Hosting Services

Test your skills and get Discount on any hosting plan

Use code:

Skills
Get Started
29.10.2024
1 +1

Writing Scripts in Linux Bash: A Complete Guide for Beginners and Sysadmins

Bash scripting is one of the most powerful skills a Linux user, developer, or system administrator can develop. Whether you're managing a single server or orchestrating complex automated workflows across an entire infrastructure, mastering Bash scripting dramatically reduces manual effort, minimizes human error, and unlocks the full potential of your Linux environment.

In this comprehensive guide, we'll walk you through everything you need to know about writing Bash scripts — from creating your very first file to working with variables, conditionals, loops, functions, arguments, and debugging techniques. Practical, copy-paste-ready examples are included throughout.

What Is a Bash Script?

A Bash script is a plain text file containing an ordered sequence of commands interpreted and executed by the Bash shell (Bourne Again SHell). Bash is the default interactive shell on the vast majority of Linux distributions, which makes it universally available and immediately practical.

Rather than typing the same sequence of commands repeatedly in a terminal, you write them once inside a script file and execute it on demand — or schedule it to run automatically.

Common Use Cases for Bash Scripts

  • File management — copying, moving, renaming, archiving, and deleting files in bulk
  • System administration — monitoring processes, managing users, checking disk usage
  • Software automation — installing packages, configuring services, deploying applications
  • Backup and recovery — creating scheduled, incremental, or full system backups
  • Log parsing and reporting — filtering and summarizing log data for analysis
  • Server provisioning — automating the initial setup of a new VPS Hosting or dedicated server environment

Prerequisites

To follow this guide, you need:

  • A Linux system (local machine, VM, or remote server)
  • Terminal access with a user account (root or sudo privileges for some operations)
  • A basic familiarity with the Linux command line

If you're working on a remote server, AlexHost's VPS Hosting plans give you full root SSH access, making them ideal for practicing and deploying Bash scripts in a real-world environment.

Step 1: Create a Bash Script File

Open your terminal and use any text editor to create a new file with the .sh extension. The .sh extension is a widely adopted convention that signals the file is a shell script, though it is not technically required by the interpreter.

nano myscript.sh

You can substitute nano with vim, gedit, micro, or any other editor you prefer.

Step 2: Add the Shebang Line (#!)

The very first line of every Bash script must be the shebang — a special directive that tells the operating system which interpreter to use when executing the file.

#!/bin/bash

This line instructs the kernel to pass the script to /bin/bash for execution, regardless of which shell the current user has set as their default. Always include it — omitting the shebang can cause scripts to behave unpredictably across different environments.

> Tip: On some modern systems, you may also see #!/usr/bin/env bash, which is a more portable alternative that locates the Bash binary dynamically via the PATH.

Step 3: Write Your Commands

After the shebang, add the commands you want the script to execute. Here is a simple example that greets the current user and displays useful system information:

#!/bin/bash

# A simple script to greet the user and display system info
echo "Hello, $USER! Welcome back."
echo "Today's date and time: $(date)"
echo "Your current working directory: $(pwd)"
echo "System hostname: $(hostname)"

Explanation of Key Elements

ElementDescription
echoPrints text or variable values to the terminal (standard output)
$USERA built-in environment variable holding the current username
$(date)Command substitution — executes date and inserts its output inline
$(pwd)Inserts the present working directory path
$(hostname)Inserts the system's hostname
#Begins a comment — ignored by the interpreter, used for documentation

Step 4: Make the Script Executable

Before you can run the script directly, you must grant it execute permissions using the chmod command:

chmod +x myscript.sh

This sets the execute bit for the file owner. To verify the permissions were applied correctly, run:

ls -l myscript.sh

You should see something like -rwxr-xr-x, where the x characters confirm execute permission.

Step 5: Run the Script

Execute the script from the same directory using the following syntax:

./myscript.sh

The ./ prefix tells the shell to look for the file in the current directory rather than searching the system PATH. You should see the output printed directly in your terminal.

Alternatively, you can invoke it explicitly with the interpreter:

bash myscript.sh

Variables in Bash Scripts

Variables allow you to store and reuse data throughout your script. They can hold strings, integers, file paths, or the output of commands.

Defining and Using Variables

#!/bin/bash

# Define variables
server_name="web-server-01"
max_connections=500
backup_dir="/var/backups"

# Use variables
echo "Server: $server_name"
echo "Max connections allowed: $max_connections"
echo "Backup directory: $backup_dir"

Important Rules for Variables

  • No spaces around the = sign when assigning a value (name="value" is correct; name = "value" is not)
  • Prefix the variable name with $ when reading its value: $variable_name
  • Use curly braces for clarity in complex strings: ${variable_name}
  • Variable names are case-sensitive: $Name and $name are different variables

Capturing Command Output in a Variable

#!/bin/bash

current_date=$(date +"%Y-%m-%d")
disk_usage=$(df -h / | awk 'NR==2 {print $5}')

echo "Date: $current_date"
echo "Root partition usage: $disk_usage"

Conditional Statements in Bash

Conditional logic allows your script to make decisions and execute different code paths based on evaluated conditions.

Basic if / elif / else Structure

#!/bin/bash

echo "Enter a number between 1 and 100:"
read user_input

if [ "$user_input" -ge 1 ] && [ "$user_input" -le 50 ]; then
    echo "Your number is in the lower half (1–50)."
elif [ "$user_input" -ge 51 ] && [ "$user_input" -le 100 ]; then
    echo "Your number is in the upper half (51–100)."
else
    echo "Your number is outside the valid range."
fi

Common Comparison Operators

OperatorMeaning
-eqEqual to
-neNot equal to
-gtGreater than
-ltLess than
-geGreater than or equal to
-leLess than or equal to
-zString is empty
-nString is not empty
-fFile exists and is a regular file
-dDirectory exists

Checking if a File Exists

#!/bin/bash

config_file="/etc/nginx/nginx.conf"

if [ -f "$config_file" ]; then
    echo "Configuration file found: $config_file"
else
    echo "ERROR: Configuration file not found at $config_file"
    exit 1
fi

Loops in Bash Scripts

Loops allow you to repeat a block of commands multiple times, either over a defined range, a list of items, or until a condition changes.

for Loop — Iterating Over a Range

#!/bin/bash

echo "Counting from 1 to 5:"
for i in {1..5}; do
    echo "  Iteration: $i"
done

for Loop — Iterating Over a List of Items

#!/bin/bash

servers=("web-01" "web-02" "db-01" "cache-01")

for server in "${servers[@]}"; do
    echo "Pinging server: $server"
    ping -c 1 "$server" &>/dev/null && echo "  ✔ $server is reachable" || echo "  ✘ $server is unreachable"
done

while Loop — Running Until a Condition Is False

#!/bin/bash

counter=1

while [ $counter -le 5 ]; do
    echo "Counter value: $counter"
    counter=$((counter + 1))
done

echo "Loop complete."

until Loop — Running Until a Condition Becomes True

#!/bin/bash

attempts=0

until [ $attempts -ge 3 ]; do
    echo "Attempt $((attempts + 1))..."
    attempts=$((attempts + 1))
done

echo "Maximum attempts reached."

Functions in Bash Scripts

Functions let you encapsulate reusable blocks of logic, making your scripts cleaner, more modular, and easier to maintain — especially as they grow in complexity.

Defining and Calling a Function

#!/bin/bash

# Define the function
greet_user() {
    local username="$1"
    echo "Hello, $username! Your session started at $(date +"%H:%M:%S")."
}

# Call the function with arguments
greet_user "Alice"
greet_user "Bob"

A Practical Function: Checking Service Status

#!/bin/bash

check_service() {
    local service_name="$1"
    if systemctl is-active --quiet "$service_name"; then
        echo "✔ $service_name is running."
    else
        echo "✘ $service_name is NOT running. Attempting to start..."
        systemctl start "$service_name" && echo "  Started successfully." || echo "  Failed to start $service_name."
    fi
}

check_service "nginx"
check_service "mysql"
check_service "ssh"

> Note: The local keyword restricts a variable's scope to within the function, preventing unintended side effects in larger scripts.

Working with Command-Line Arguments

Bash scripts can accept input directly from the command line when they are invoked, enabling flexible, reusable scripts that behave differently based on provided parameters.

Special Argument Variables

VariableDescription
$0The name of the script itself
$1, $2, $3The first, second, and third positional arguments
$#The total number of arguments passed
$@All arguments as a list
$*All arguments as a single string
$?The exit status of the last executed command

Example: A Script That Accepts Arguments

#!/bin/bash

# Validate that exactly two arguments were provided
if [ $# -ne 2 ]; then
    echo "Usage: $0 <source_directory> <destination_directory>"
    exit 1
fi

source_dir="$1"
dest_dir="$2"

# Check that the source directory exists
if [ ! -d "$source_dir" ]; then
    echo "ERROR: Source directory '$source_dir' does not exist."
    exit 1
fi

echo "Copying files from '$source_dir' to '$dest_dir'..."
cp -r "$source_dir" "$dest_dir" && echo "Copy completed successfully." || echo "Copy failed."

Run it like this:

./myscript.sh /var/www/html /var/backups/html_backup

Exit Codes and Error Handling

Robust Bash scripts always handle errors gracefully. Every command in Linux returns an exit code: 0 indicates success, and any non-zero value indicates an error.

Using exit and $?

#!/bin/bash

# Attempt to create a directory
mkdir /tmp/test_directory

if [ $? -eq 0 ]; then
    echo "Directory created successfully."
else
    echo "Failed to create directory."
    exit 1
fi

Using set -e for Automatic Error Handling

Adding set -e at the top of your script causes it to exit immediately if any command returns a non-zero exit code — a best practice for production scripts:

#!/bin/bash
set -e          # Exit on any error
set -u          # Treat unset variables as errors
set -o pipefail # Catch errors in pipelines

echo "Starting deployment..."
cd /var/www/html
git pull origin main
systemctl reload nginx
echo "Deployment complete."

Debugging Bash Scripts

Even experienced developers write scripts with bugs. Bash provides built-in tools to help you trace and fix problems efficiently.

Method 1: Run with -x Flag (Trace Mode)

bash -x myscript.sh

This prints every command to the terminal as it is executed, prefixed with +, along with the values of any expanded variables. It is the most commonly used debugging technique.

Method 2: Add set -x Inside the Script

You can enable and disable tracing for specific sections of your script:

#!/bin/bash

echo "Normal execution..."

set -x  # Enable tracing
cp /source/file /destination/
chmod 644 /destination/file
set +x  # Disable tracing

echo "Tracing disabled again."

Method 3: Use echo Statements for Checkpoints

Strategically placed echo statements help you verify variable values and confirm that execution has reached a specific point in the script:

echo "DEBUG: backup_dir = $backup_dir"
echo "DEBUG: Reached checkpoint before rsync"

Practical Real-World Example: Automated Backup Script

Here is a complete, production-ready Bash script that demonstrates many of the concepts covered in this guide:

#!/bin/bash
set -euo pipefail

# ============================================================
# Automated Backup Script
# Description: Backs up a specified directory with a timestamp
# ============================================================

# Configuration
SOURCE_DIR="/var/www/html"
BACKUP_ROOT="/var/backups/web"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
BACKUP_NAME="backup_${TIMESTAMP}.tar.gz"
BACKUP_PATH="${BACKUP_ROOT}/${BACKUP_NAME}"
RETENTION_DAYS=7
LOG_FILE="/var/log/backup.log"

# Logging function
log() {
    echo "[$(date +"%Y-%m-%d %H:%M:%S")] $1" | tee -a "$LOG_FILE"
}

# Validate source directory
if [ ! -d "$SOURCE_DIR" ]; then
    log "ERROR: Source directory '$SOURCE_DIR' not found. Aborting."
    exit 1
fi

# Create backup root if it doesn't exist
mkdir -p "$BACKUP_ROOT"

log "Starting backup of '$SOURCE_DIR'..."

# Create compressed archive
tar -czf "$BACKUP_PATH" -C "$(dirname "$SOURCE_DIR")" "$(basename "$SOURCE_DIR")"

log "Backup created: $BACKUP_PATH ($(du -sh "$BACKUP_PATH" | cut -f1))"

# Remove backups older than retention period
log "Removing backups older than ${RETENTION_DAYS} days..."
find "$BACKUP_ROOT" -name "backup_*.tar.gz" -mtime +"$RETENTION_DAYS" -delete

log "Backup process completed successfully."

This type of script is invaluable on any production server. If you're running a website or application on Dedicated Servers or a VPS, automating your backups with a script like this — combined with a cron job — ensures your data is always protected without manual intervention.

Scheduling Bash Scripts with Cron

To run your Bash scripts automatically on a schedule, use cron, the Linux task scheduler. Edit your crontab with:

crontab -e

Add a line in the following format:

# Run backup script every day at 2:00 AM
0 2 * * * /path/to/backup.sh >> /var/log/backup_cron.log 2>&1

Cron syntax: minute hour day-of-month month day-of-week command

Best Practices for Writing Bash Scripts

Following these conventions will make your scripts more reliable, readable, and maintainable:

  1. Always include the shebang (#!/bin/bash) on the first line
  2. Use set -euo pipefail in production scripts to catch errors early
  3. Quote your variables ("$variable") to prevent word splitting and globbing issues
  4. Use meaningful variable namesbackup_directory is clearer than bd
  5. Comment your code — explain *why*, not just *what*
  6. Validate inputs — check that required arguments and files exist before proceeding
  7. Use functions to organize complex logic into reusable, named blocks
  8. Test in a safe environment before running scripts on production systems
  9. Use local variables inside functions to avoid polluting the global scope
  10. Log important actions to a file so you can audit script behavior later

Taking Your Bash Skills Further

Once you're comfortable with the fundamentals, consider exploring these advanced topics:

  • Regular expressions with grep, sed, and awk for powerful text processing
  • Here documents (heredoc) for embedding multi-line strings in scripts
  • Process substitution and named pipes for complex data pipelines
  • Signal handling with trap for graceful script termination
  • Associative arrays (Bash 4+) for key-value data structures
  • Script libraries — sourcing common functions from a shared file with source

If you're managing web applications, databases, or email infrastructure, Bash scripting pairs naturally with services like Shared Web Hosting for smaller projects, or a fully managed VPS with cPanel for environments where you want a graphical interface alongside shell access.

For teams running data-intensive workloads or machine learning pipelines, Bash scripts are equally valuable for orchestrating jobs on GPU Hosting infrastructure — automating model training runs, managing datasets, and handling environment setup.

Conclusion

Bash scripting is an indispensable skill for anyone working with Linux — whether you're a beginner automating your first repetitive task or a senior systems administrator managing complex server infrastructure. The concepts covered in this guide — file creation, variables, conditionals, loops, functions, argument handling, error management, and debugging — form the complete foundation you need to write reliable, production-quality scripts.

Start small: automate one task you perform manually every day. As your confidence grows, combine these building blocks into increasingly sophisticated tools that save hours of work, reduce the risk of human error, and give you precise, repeatable control over your systems.

For the best environment to practice and deploy your Bash scripts, explore AlexHost's range of Linux-based VPS Hosting plans — featuring full root access, SSD storage, and flexible configurations designed for developers and sysadmins alike.

15%

Save 15% on All Hosting Services

Test your skills and get Discount on any hosting plan

Use code:

Skills
Get Started