Live
Cloudflare WAF adds default‑log rules for Brotli encoding and Next.js image endpointGPU Capacity Planning: Validate Outcomes Before Adding HardwareEmbedding Vercel’s Zig Coding Agent: Architecture and Ops ImpactGemini 4 Argon trims ADK session prep and import latency by up to 40%Rethinking CI/CD: The Sensor Limits of an Agentic Software FactoryResolving the Kubernetes Autoscaling Conflict: Independent Controllers vs. Autonomous CoordinationAI‑Generated Queries Move Data Interface to Embedded DuckDB for Disaster‑Recovery AnalyticsIntegrating NVIDIA Earth-2 StormScope EU: Architecture, Ops, and Security TakeawaysCloudflare WAF adds default‑log rules for Brotli encoding and Next.js image endpointGPU Capacity Planning: Validate Outcomes Before Adding HardwareEmbedding Vercel’s Zig Coding Agent: Architecture and Ops ImpactGemini 4 Argon trims ADK session prep and import latency by up to 40%Rethinking CI/CD: The Sensor Limits of an Agentic Software FactoryResolving the Kubernetes Autoscaling Conflict: Independent Controllers vs. Autonomous CoordinationAI‑Generated Queries Move Data Interface to Embedded DuckDB for Disaster‑Recovery AnalyticsIntegrating NVIDIA Earth-2 StormScope EU: Architecture, Ops, and Security Takeaways
LINUX

Bash Scripting for DevOps: Variables, Loops and Automation

Overview

This tutorial covers the core Bash scripting skills every Linux systems administrator needs: declaring and using variables, writing for and while loops, conditional logic, and building practical automation scripts. By the end, you will have written working scripts you can deploy immediately in a DevOps environment.

Prerequisites:

  • Basic Linux command-line familiarity (cd, ls, cat, chmod)
  • A Linux environment — Ubuntu 22.04, RHEL 9, or any modern distro
  • A text editor (vim, nano, or VS Code with remote SSH)

Why this matters for LFCS: The Linux Foundation Certified SysAdmin exam tests your ability to automate administrative tasks using shell scripting. Expect hands-on tasks that require writing scripts to process files, manage users, and schedule jobs. Scripting is not optional — it is a core exam domain.

Getting Started

Verify your Bash version and create a working directory before writing any scripts.

# Check Bash version (LFCS expects 4.x or higher)
bash --version

# Create a dedicated workspace
mkdir -p ~/devops-scripts && cd ~/devops-scripts

# Create your first script file
touch hello_devops.sh
chmod +x hello_devops.sh

Every Bash script must begin with a shebang line that tells the kernel which interpreter to use. Never omit it.

#!/usr/bin/env bash
# hello_devops.sh — starter script
echo "CloudNinjas DevOps environment ready"

Run it two ways and understand the difference:

# Method 1: Execute directly (requires chmod +x)
./hello_devops.sh

# Method 2: Pass to interpreter explicitly
bash hello_devops.sh

Variables and Parameter Handling

In Bash, variables store data with no spaces around the equals sign — this is the most common beginner mistake and it will fail silently or throw an error on the exam.

#!/usr/bin/env bash
# variables_demo.sh

# String variable — no spaces around =
ENV_NAME="production"
SERVER_COUNT=5
LOG_DIR="/var/log/app"

# Reference variables with $
echo "Environment: ${ENV_NAME}"
echo "Servers: ${SERVER_COUNT}"
echo "Log path: ${LOG_DIR}"

# Command substitution — capture command output into a variable
CURRENT_USER=$(whoami)
HOSTNAME_VAR=$(hostname -f)
DISK_USAGE=$(df -h / | awk 'NR==2 {print $5}')

echo "Running as: ${CURRENT_USER} on ${HOSTNAME_VAR}"
echo "Root disk usage: ${DISK_USAGE}"

Special variables are critical for writing scripts that accept arguments from the command line:

#!/usr/bin/env bash
# args_demo.sh — run as: ./args_demo.sh webserver 3

SERVICE_NAME=$1   # First argument
INSTANCE_COUNT=$2  # Second argument

echo "Service: ${SERVICE_NAME}"
echo "Instances requested: ${INSTANCE_COUNT}"
echo "Total args passed: $#"
echo "All args: $@"
echo "This script PID: $$"

# Always validate input
if [[ -z "${SERVICE_NAME}" ]]; then
  echo "ERROR: service name is required"
  echo "Usage: $0  "
  exit 1
fi

Common pitfalls:

  • Using $var instead of ${var} inside strings — always use braces for clarity
  • Forgetting quotes around variables that may contain spaces: use "${VAR}" not ${VAR}
  • Using == inside single brackets [ ] instead of double brackets [[ ]] — prefer double brackets in modern Bash

Loops and Conditionals for Automation

For loops are the workhorse of infrastructure automation — iterating over server lists, files, or numeric ranges.

#!/usr/bin/env bash
# loop_demo.sh

# Iterate over a static list of hosts
SERVERS=("web01" "web02" "web03" "db01")

for SERVER in "${SERVERS[@]}"; do
  echo "Checking connectivity to: ${SERVER}"
  ping -c 1 -W 2 "${SERVER}" &>/dev/null && \
    echo "  [OK]  ${SERVER} is reachable" || \
    echo "  [FAIL] ${SERVER} is unreachable"
done

# Numeric range loop — provision N resources
for i in $(seq 1 5); do
  echo "Creating volume-${i}"
done

# Loop over files matching a pattern
for LOG_FILE in /var/log/*.log; do
  SIZE=$(du -sh "${LOG_FILE}" 2>/dev/null | cut -f1)
  echo "${LOG_FILE}: ${SIZE}"
done

While loops are ideal for polling, retries, and reading file input line by line:

#!/usr/bin/env bash
# retry_demo.sh — poll until a service is healthy

SERVICE="nginx"
MAX_RETRIES=10
RETRY_INTERVAL=3
ATTEMPT=1

while [[ ${ATTEMPT} -le ${MAX_RETRIES} ]]; do
  if systemctl is-active --quiet "${SERVICE}"; then
    echo "[SUCCESS] ${SERVICE} is running after ${ATTEMPT} attempt(s)"
    exit 0
  fi
  echo "[WAIT] Attempt ${ATTEMPT}/${MAX_RETRIES} — retrying in ${RETRY_INTERVAL}s"
  sleep ${RETRY_INTERVAL}
  ((ATTEMPT++))
done

echo "[ERROR] ${SERVICE} failed to start after ${MAX_RETRIES} attempts"
exit 1

A practical real-world automation script combining variables, loops, and conditionals — bulk user creation from a CSV file:

#!/usr/bin/env bash
# bulk_users.sh — create users from users.csv
# CSV format: username,group,shell
# Example: devuser1,developers,/bin/bash

USER_FILE="${1:-users.csv}"
LOG_FILE="/var/log/user_creation.log"

[[ ! -f "${USER_FILE}" ]] && { echo "File not found: ${USER_FILE}"; exit 1; }

while IFS=',' read -r USERNAME GROUP SHELL; do
  # Skip comment lines
  [[ "${USERNAME}" =~ ^# ]] && continue

  # Create group if it does not exist
  if ! getent group "${GROUP}" &>/dev/null; then
    groupadd "${GROUP}"
    echo "$(date): Created group ${GROUP}" >> "${LOG_FILE}"
  fi

  # Create user if they do not exist
  if ! id "${USERNAME}" &>/dev/null; then
    useradd -m -g "${GROUP}" -s "${SHELL}" "${USERNAME}"
    echo "$(date): Created user ${USERNAME} in group ${GROUP}" >> "${LOG_FILE}"
    echo "[OK] Created: ${USERNAME}"
  else
    echo "[SKIP] User already exists: ${USERNAME}"
  fi
done < "${USER_FILE}"

Best practices:

  • Always use set -euo pipefail at the top of production scripts — exits on error, undefined variables, and pipe failures
  • Log all destructive actions with timestamps using $(date)
  • Use exit 0 for success and non-zero exit codes for specific failure types
  • Quote every variable expansion to handle filenames with spaces

Exam Tips for Linux Foundation Certified SysAdmin (LFCS)

The LFCS exam is performance-based — you execute real tasks on live VMs with no multiple choice. These scripting patterns appear repeatedly:

Key concepts tested:

  • Writing scripts that accept and validate positional arguments ($1, $2, $#)
  • Using find combined with loops to process files by age, size, or permission
  • Scheduling scripts with cron — know crontab syntax cold (* * * * * = minute hour day month weekday)
  • Redirecting stdout and stderr independently: command > out.log 2> err.log
  • Exit code checking with $? and short-circuit operators && and ||

Common exam scenarios:

  1. Write a script to archive log files older than 7 days
  2. Create a script that checks disk usage and emails an alert if above 80%
  3. Automate user creation with specific UID ranges and home directories

Quick reference commands to memorize:

# Strict mode — add to every exam script
set -euo pipefail

# Check if running as root
[[ $(id -u) -ne 0 ]] && { echo "Must run as root"; exit 1; }

# Find and delete files older than 7 days
find /var/log/app -name "*.log" -mtime +7 -delete

# Check last command exit code
if [[ $? -ne 0 ]]; then echo "Command failed"; fi

# Schedule script to run daily at 2am via cron
# 0 2 * * * /usr/local/bin/cleanup.sh >> /var/log/cleanup.log 2>&1

# Read file line by line safely
while IFS= read -r LINE; do echo "${LINE}"; done < input.txt

Summary

You have covered the Bash scripting fundamentals that underpin real DevOps workflows and the LFCS certification exam:

  • Variables — declaration, command substitution, special parameters, and safe quoting practices
  • Loops — for loops over arrays and files, while loops for polling and retry logic
  • Conditionals — input validation, file checks, and service state verification
  • Automation patterns — bulk user creation, health checks, and log management
  • Best practices — strict mode, logging, exit codes, and argument validation

Next steps: Practice writing scripts without an IDE — the LFCS exam environment is terminal-only. Work through at least five scripts daily, focusing on find, awk, and sed integration with loops. Set up a cron job for one of the scripts from this tutorial to solidify the scheduling workflow.

Ready to go deeper? Check out the CloudNinjas LFCS Certification Study Guide for full domain coverage, practice labs, and exam-day strategy.