If you're typing the same commands over and over, you're doing it wrong. Bash scripting turns repetitive command-line tasks into automated, repeatable scripts that save hours of work. As a DevOps engineer, scripting isn't optional—it's how you work smarter, not harder. In this hands-on guide, you'll write your first scripts and learn the fundamentals that power every automation task.

1. Learning Objectives

By the end of this lesson, you will be able to:

  • Create and execute your first Bash script
  • Use the shebang (#!/bin/bash) correctly
  • Work with variables and user input (read)
  • Understand and use exit codes ($?, exit 0)
  • Make scripts executable with chmod +x
  • Create a practical system information script

2. Why This Matters (Real-World Scenario)

Real-world scenario: Every morning, you need to check 20 servers for disk space, memory usage, and running services. Doing this manually takes 45 minutes. With a Bash script, you write it once and run it in 5 seconds.

Another scenario: Your team deploys code 10 times per day. Each deployment requires 15 manual commands. A Bash script reduces this to one command: ./deploy.sh.

3. Core Concepts

What is a Bash Script?

A Bash script is simply a text file containing a series of commands that you would normally type in the terminal. Instead of typing them one by one, Bash runs them all sequentially.

#!/bin/bash
# This is a comment - Bash ignores this line
echo "Hello, World!"
echo "Current date: $(date)"
echo "Logged in as: $(whoami)"
Your first Bash script

The Shebang (#!/bin/bash) - THE MOST IMPORTANT LINE

The shebang (#!) tells your system which interpreter to use. Without it, your system might try to run the script with the wrong shell (or not at all).

Comments (Explaining Your Code)

#!/bin/bash
# This is a single-line comment
# Comments are for humans, not computers

echo "This runs"  # You can comment after a command as well

: '
This is a multi-line comment
It can span multiple lines
Useful for longer explanations
'
Comment styles in Bash

Making Scripts Executable

Before you can run a script, you need to make it executable. This is a safety feature—you can't accidentally run a script.

# Create the script file
nano myscript.sh

# Make it executable
chmod +x myscript.sh

# Run it
./myscript.sh

# Run it from anywhere (add to PATH later)
# Alternative: run with bash command (doesn't need +x)
bash myscript.sh
Making and running scripts
kubectl get pods -w
$ chmod +x myscript.sh
$ ls -l myscript.sh
-rwxr-xr-x 1 user user 45 Jan 17 10:00 myscript.sh
$ ./myscript.sh
Hello, World!
The 'x' in -rwxr-xr-x means executable

Variables: Storing Data

#!/bin/bash
# Variables - NO spaces around = !!!
name="Alex"                  # String
age=30                        # Number
current_date=$(date)          # Command output
files_count=$(ls | wc -l)    # Another command

# Using variables - use $
echo "My name is $name"
echo "I am $age years old"
echo "Today is $current_date"
echo "There are $files_count files here"

# Variable naming rules
# Valid: MY_VAR, myVar, _my_var, var123
# Invalid: 123var (can't start with number), my-var (no hyphens)
Working with variables
kubectl get pods -w
$ ./variables.sh
My name is Alex
I am 30 years old
Today is Thu Jan 17 10:00:00 UTC 2025
There are 12 files here
Variables in action

User Input: Making Scripts Interactive

#!/bin/bash
# Asking for user input

echo "What is your name?"
read username
echo "Hello, $username!"

# Prompt with the same line
read -p "Enter your age: " age
echo "You are $age years old"

# Silent input (for passwords)
read -sp "Enter password: " password
echo "Password received"

# Default value if user presses enter
read -p "Enter directory to backup [default: /home]: " backup_dir
backup_dir=${backup_dir:-/home}
echo "Backing up $backup_dir"
Getting input from users
kubectl get pods -w
$ ./user_input.sh
What is your name?
Alex
Hello, Alex!
Enter your age: 30
You are 30 years old
Enter password:
Password received
Enter directory to backup [default: /home]:
Backing up /home
Interactive script with user input

Exit Codes: Did Your Script Succeed?

Every command in Linux returns an exit code:
0 = Success
1-255 = Failure (different numbers mean different errors)

#!/bin/bash
# Exit codes and error handling

echo "This command will succeed"
ls /tmp
echo "Exit code: $?"  # Should be 0

echo "This command will fail"
ls /nonexistent_directory
echo "Exit code: $?"  # Should be non-zero

# Set custom exit code
if [ -f "/etc/passwd" ]; then
    echo "File exists"
    exit 0  # Success
else
    echo "File not found"
    exit 1  # Failure
fi
Using exit codes
kubectl get pods -w
$ ./exit_codes.sh
This command will succeed
Exit code: 0
This command will fail
ls: cannot access '/nonexistent_directory': No such file or directory
Exit code: 2
File exists
Exit codes tell you if commands succeeded

4. Hands-on Practice Lab

Setup Your Practice Environment

mkdir ~/bash-practice
cd ~/bash-practice
touch first_script.sh second_script.sh
chmod +x *.sh
Create practice directory

Exercise 1: System Information Script

#!/bin/bash
# system_info.sh - Display system information

echo "====================================="
echo "     SYSTEM INFORMATION REPORT"
echo "====================================="
echo ""

# User info
echo "User Information:"
echo "  Username: $(whoami)"
echo "  Home directory: $HOME"
echo "  Current shell: $SHELL"
echo ""

# System info
echo "System Information:"
echo "  Hostname: $(hostname)"
echo "  OS: $(uname -o)"
echo "  Kernel: $(uname -r)"
echo "  Architecture: $(uname -m)"
echo "  Uptime: $(uptime -p)"
echo ""

# Disk usage
echo "Disk Usage:"
df -h | head -4
echo ""

# Memory usage
echo "Memory Usage:"
free -h
echo ""

# Current processes
echo "Top 5 CPU-consuming processes:"
ps aux --sort=-%cpu | head -6
echo ""

echo "Report generated on: $(date)"
Complete system information script

Exercise 2: Interactive Backup Script

#!/bin/bash
# backup.sh - Create a timestamped backup

# Color codes for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

echo -e "${GREEN}=== Backup Utility ===${NC}"

# Get source directory
read -p "Enter directory to backup: " source_dir

# Check if source exists
if [ ! -d "$source_dir" ]; then
    echo -e "${RED}Error: Directory '$source_dir' does not exist!${NC}"
    exit 1
fi

# Get backup destination (default: current directory)
read -p "Enter backup destination [default: current directory]: " dest_dir
dest_dir=${dest_dir:-.}

# Create backup filename with timestamp
timestamp=$(date +"%Y%m%d_%H%M%S")
backup_name="backup_$(basename "$source_dir")_$timestamp.tar.gz"

# Perform backup
echo -e "${YELLOW}Backing up $source_dir to $dest_dir/$backup_name...${NC}"
tar -czf "$dest_dir/$backup_name" "$source_dir"

# Check if backup succeeded
if [ $? -eq 0 ]; then
    echo -e "${GREEN}✓ Backup successful!${NC}"
    echo "Backup saved as: $dest_dir/$backup_name"
    ls -lh "$dest_dir/$backup_name"
else
    echo -e "${RED}✗ Backup failed!${NC}"
    exit 1
fi
Interactive backup script with error handling

5. Common Errors & Solutions

6. Summary Checklist

7. Next Steps

Next lesson: Bash Lesson 2.2: Conditionals, Loops, and Functions

You'll learn to:

  • Use if/else statements for decision making
  • Loop with for and while
  • Create reusable functions
  • Compare strings and numbers

Practice resources:

Gataya Med

DevOps Engineer & Backend Developer. Sharing insights on cloud, automation, and scalable systems.

Comments (0)

Sarah Chen January 17, 2025

This is exactly what I needed! The initContainer approach solved our migration issues completely. Thanks for the detailed guide!

Reply

Leave a Comment