Skip to content
First 20 students get 50% discount.
Login/Register
Call: 123 4561 5523
Email: info@edublink.co
legendarywaysacademy.comlegendarywaysacademy.com
  • Category
    • Business
    • Cooking
    • Digital Marketing
    • Fitness
    • Motivation
    • Online Art
    • Photography
    • Programming
    • Yoga
  • Home
      • EduBlink EducationHOT
      • Distant Learning
      • University
      • Online AcademyHOT
      • Modern Schooling
      • Kitchen Coach
      • Yoga Instructor
      • Kindergarten
      • Language Academy
      • Remote Training
      • Business Coach
      • Motivation
      • Programming
      • Online Art
      • Sales CoachNEW
      • Quran LearningNEW
      • Gym TrainingNEW
      • PhotographyNEW
      • Health CoachNEWHOT
      • Digital MarketingNEWHOT
  • Pages
    • About Us
      • About Us 1
      • About Us 2
      • About Us 3
    • Instructors
      • Instructor 1
      • Instructor 2
      • Instructor 3
      • Instructor Details
    • Event Pages
      • Event Style 1
      • Event Details
    • Shop Pages
      • Product Details
    • Zoom Meeting
    • FAQ’s
    • Instructor Registration
    • Student Registration
    • Pricing Table
    • Privacy Policy
    • Coming Soon
    • 404 Page
  • Courses
    • Courses Style
      • Course Style 1
      • Course Style 2
      • Course Style 3
      • Course Style 4
      • Course Style 5
      • Course Style 6
      • Course Style 7
      • Course Style 8
      • Course Style 9
      • Course Style 10
      • Course Style 11
      • Course Style 12
      • Course Style 13
    • Course Details
      • Course Details 1
      • Course Details 2
      • Course Details 3
      • Course Details 4
      • Course Details 5
    • Course Filter
      • Filter Sidebar Left
      • Filter Sidebar Right
      • Filter Category
  • Blog
    • Blog Style 1
    • Blog Style 2
    • Blog Standard
    • Blog Details
  • Contact
    • Contact Us
    • Contact Me
0

Currently Empty: $0.00

Continue shopping

Try for free
legendarywaysacademy.comlegendarywaysacademy.com
  • Home
      • EduBlink EducationHOT
      • Distant Learning
      • University
      • Online AcademyHOT
      • Modern Schooling
      • Kitchen Coach
      • Yoga Instructor
      • Kindergarten
      • Language Academy
      • Remote Training
      • Business Coach
      • Motivation
      • Programming
      • Online Art
      • Sales CoachNEW
      • Quran LearningNEW
      • Gym TrainingNEW
      • PhotographyNEW
      • Health CoachNEWHOT
      • Digital MarketingNEWHOT
  • Pages
    • About Us
      • About Us 1
      • About Us 2
      • About Us 3
    • Instructors
      • Instructor 1
      • Instructor 2
      • Instructor 3
      • Instructor Details
    • Event Pages
      • Event Style 1
      • Event Details
    • Shop Pages
      • Product Details
    • Zoom Meeting
    • FAQ’s
    • Instructor Registration
    • Student Registration
    • Pricing Table
    • Privacy Policy
    • Coming Soon
    • 404 Page
  • Courses
    • Courses Style
      • Course Style 1
      • Course Style 2
      • Course Style 3
      • Course Style 4
      • Course Style 5
      • Course Style 6
      • Course Style 7
      • Course Style 8
      • Course Style 9
      • Course Style 10
      • Course Style 11
      • Course Style 12
      • Course Style 13
    • Course Details
      • Course Details 1
      • Course Details 2
      • Course Details 3
      • Course Details 4
      • Course Details 5
    • Course Filter
      • Filter Sidebar Left
      • Filter Sidebar Right
      • Filter Category
  • Blog
    • Blog Style 1
    • Blog Style 2
    • Blog Standard
    • Blog Details
  • Contact
    • Contact Us
    • Contact Me

Bash Scripting for DevOps

  • Home
  • DevOps Topics
  • Bash Scripting for DevOps
Breadcrumb Abstract Shape
Breadcrumb Abstract Shape
Breadcrumb Abstract Shape
Bash scripting illustration showing a terminal window running a for loop over log files
Legendary Ways Academy · Foundations

Bash Scripting, Automate What You’d Otherwise Repeat

Every deploy script, cron job, and CI pipeline step you’ll write early in a DevOps career is a Bash script. This is the guide that takes you from single commands to real automation.

Next: Git and GitHub All Topics
Copy-paste scripts
Real deploy example
Error handling
Bash scripting illustration showing a terminal window running a for loop over log files

The moment you find yourself running the same three or four commands in sequence more than twice, that’s the moment a Bash script should replace them. Bash scripting is the practice of writing those commands into a reusable file, the shell runs top to bottom, so what used to take five manual steps and a chance to mistype something becomes one reliable command. In DevOps specifically, Bash is everywhere: CI/CD pipeline steps are frequently just Bash commands, deploy scripts are Bash, cron jobs that rotate logs or clean up disk space are Bash, and Dockerfile RUN instructions execute in a shell that understands the same syntax.

This guide walks through the actual building blocks, variables, conditionals, loops, functions, and argument handling, then ties them together into a realistic deploy script, and covers the error-handling habits that separate a script you can trust in production from one that fails silently and leaves a mess. Along the way it also covers scheduling scripts with cron, catching mistakes automatically with shellcheck, and the specific pitfalls that trip up nearly every engineer’s early scripts, unquoted variables, missing error handling, and assumptions about the environment a script will actually run in.

None of this requires a programming background. Bash’s syntax is unusual compared to languages like Python or JavaScript, but the concepts, variables, conditionals, loops, are the same ones you’d encounter in any language, applied to the specific job of chaining shell commands together reliably.

The Building Blocks

Variables

Store and reuse values, from a version number to a file path, without repeating them throughout the script.

Conditionals

if/else logic that lets a script branch based on whether a command succeeded or a value matches.

Loops

for and while loops that repeat an action across a list of files, servers, or values.

Functions

Reusable blocks of logic you can call by name instead of copy-pasting the same lines repeatedly.

Anatomy of a Script

Every Bash script starts with a shebang line, #!/bin/bash, telling the system which interpreter should run the file. After that, it’s just the same commands you’d type interactively, executed in order. Making the file executable with chmod +x lets you run it directly as ./script.sh instead of needing to type bash script.sh every time.

bash
#!/bin/bash
echo "Starting deploy..."
cd /var/www/app
git pull origin main
npm install
echo "Deploy complete."

This script alone already saves real time: five commands, run reliably every time in the same order, instead of typed manually and occasionally run out of sequence. Save it as deploy.sh, run chmod +x deploy.sh, and it’s callable from anywhere as a single command.

Variables and User Input

Variables hold values you’ll reuse throughout a script. Assign with = (no spaces around it, a common early syntax error) and reference with a $ prefix. Scripts can also accept arguments from the command line, referenced as $1, $2, and so on, which is how a single script can be made reusable across environments instead of hardcoded for one.

bash
#!/bin/bash
ENVIRONMENT=$1
APP_DIR="/var/www/$ENVIRONMENT"

echo "Deploying to $ENVIRONMENT"
echo "Target directory: $APP_DIR"

Run as ./deploy.sh staging, and $1 captures “staging,” letting the same script deploy to staging or production depending on the argument passed, rather than maintaining two nearly identical scripts.

Conditionals

if statements let a script make decisions, most commonly checking whether a file exists, whether a variable matches an expected value, or whether a previous command succeeded. In Bash, a command’s exit code (0 for success, anything else for failure) is what conditionals actually test, which is a slightly different mental model than most programming languages.

bash
#!/bin/bash
if [ -f "package.json" ]; then
  echo "Found package.json, installing dependencies..."
  npm install
else
  echo "No package.json found. Exiting."
  exit 1
fi

-f tests whether a file exists; other common tests include -d for a directory, -z for an empty string, and -eq for numeric equality. exit 1 stops the script and returns a non-zero exit code, signaling failure to whatever called the script, a CI pipeline included, so it can react accordingly rather than silently continuing.

Loops

for loops repeat an action across a list, whether that’s a set of files, a list of servers, or a range of numbers. while loops repeat as long as a condition stays true, useful for retry logic like waiting for a service to become healthy.

bash
#!/bin/bash
for server in web-1 web-2 web-3; do
  echo "Restarting $server..."
  ssh "$server" "sudo systemctl restart app"
done

RETRIES=0
while ! curl -sf http://localhost:8080/health; do
  echo "Waiting for service..."
  sleep 5
  RETRIES=$((RETRIES + 1))
  if [ "$RETRIES" -gt 10 ]; then
    echo "Service did not become healthy in time."
    exit 1
  fi
done

This second example is a real pattern used in deploy scripts everywhere: after restarting a service, poll a health check endpoint until it responds successfully, with a retry limit so the script fails loudly instead of hanging forever if something is actually broken.

Functions

Once a script grows past a handful of steps, functions keep it readable and avoid repeating logic. A function is defined once and called by name anywhere in the script, and can accept arguments the same way the script itself does.

bash
#!/bin/bash
log() {
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}

log "Starting deploy"
git pull origin main
log "Pulled latest code"
npm install
log "Dependencies installed"

A small logging function like this, timestamping every step, is one of the highest-value additions to any real deploy script: when something fails at 3am, timestamped output makes it far easier to see exactly which step failed and how long each prior step took.

Error Handling: The Habit That Actually Matters

The single most important line in a production Bash script is set -e near the top, which causes the script to exit immediately if any command fails, rather than continuing past a broken step as if nothing went wrong. Without it, a failed git pull in a deploy script doesn’t stop the script, it just continues on to install dependencies and restart a service against whatever code happened to be there before, often silently shipping a broken or stale deploy.

bash
#!/bin/bash
set -euo pipefail

echo "Starting deploy..."
cd /var/www/app || exit 1
git pull origin main
npm install
npm run build
sudo systemctl restart app
echo "Deploy successful."

set -euo pipefail is the standard defensive header for production scripts: -e exits on any failed command, -u treats unset variables as an error instead of silently substituting an empty string, and -o pipefail makes a pipeline (commands joined with |) fail if any command in it fails, not just the last one. Adding this single line to every script you write is one of the highest-leverage habits in this entire guide.

A Realistic End-to-End Deploy Script

Putting the pieces above together, here’s a deploy script closer to what you’d actually run in production, combining logging, error handling, a health check retry loop, and a rollback path if the deploy fails partway through.

bash
#!/bin/bash
set -euo pipefail

APP_DIR="/var/www/app"
BACKUP_DIR="/var/backups/app-$(date +%s)"

log() {
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}

log "Backing up current release to $BACKUP_DIR"
cp -r "$APP_DIR" "$BACKUP_DIR"

log "Pulling latest code"
cd "$APP_DIR"
git pull origin main

log "Installing dependencies"
npm install --production

log "Restarting service"
sudo systemctl restart app

log "Waiting for health check"
RETRIES=0
until curl -sf http://localhost:8080/health; do
  sleep 3
  RETRIES=$((RETRIES + 1))
  if [ "$RETRIES" -gt 10 ]; then
    log "Health check failed. Rolling back."
    rm -rf "$APP_DIR"
    mv "$BACKUP_DIR" "$APP_DIR"
    sudo systemctl restart app
    exit 1
  fi
done

log "Deploy successful"
rm -rf "$BACKUP_DIR"

Notice the shape of this: back up before changing anything, do the risky work, verify the result with a real health check, and automatically roll back to the known-good backup if verification fails. This exact pattern, backup, change, verify, rollback-on-failure, is the core structure of almost every reliable deployment mechanism, whether it’s a hand-written Bash script like this one or a managed platform’s built-in deploy strategy.

Common Pitfalls to Avoid

A handful of mistakes show up constantly in early Bash scripts. Unquoted variables are the most common: rm -rf $DIR becomes dangerous if $DIR is ever empty or contains spaces, since Bash will word-split it unexpectedly; writing rm -rf "$DIR" with quotes avoids this entire class of bug. Comparing strings with a single = inside [ ] works, but forgetting the spaces around it, like [ "$a"="$b" ], silently fails rather than throwing a clear error. And assuming a script’s current working directory is always what you expect is a frequent source of “works on my machine” bugs; scripts run by cron or CI often start from an unexpected directory, so use absolute paths or cd explicitly rather than relying on relative paths.

bash
# Risky: word-splitting if DIR is unset or has spaces
rm -rf $DIR

# Safe: quoted, and defaults to a safe no-op if unset
rm -rf "${DIR:?DIR is not set}"

The ${DIR:?message} syntax is a genuinely useful defensive pattern: if DIR is unset or empty, the script prints the given message and exits immediately, rather than silently running a destructive command against an unintended path (or worse, the root of the filesystem).

Scheduling Scripts With Cron

Many Bash scripts in a DevOps context don’t run on demand, they run on a schedule: nightly backups, log rotation, certificate renewal checks. cron is the standard Linux scheduler, configured through a crontab file with a five-field time expression (minute, hour, day of month, month, day of week) followed by the command to run.

bash
# Edit the current user's crontab
crontab -e

# Run a backup script every day at 2:30am
30 2 * * * /opt/scripts/backup.sh >> /var/log/backup.log 2>&1

# Run a cleanup script every Sunday at midnight
0 0 * * 0 /opt/scripts/cleanup.sh

Redirecting output with >> /var/log/backup.log 2>&1 is worth doing on every cron job by default: it captures both standard output and errors to a log file, since a failed cron job with no output redirection fails completely silently, and you’ll only discover the problem once its absence causes a bigger issue days or weeks later.

How This Connects to the Rest of DevOps

Bash scripting is the connective tissue between nearly every other DevOps topic. CI/CD pipeline steps, covered in our CI/CD pipelines guide, are frequently nothing more than a sequence of Bash commands run by the CI platform. Dockerfiles run shell commands during the build process. Terraform provisioning scripts and Kubernetes deployment automation both frequently shell out to Bash for glue logic that’s awkward to express in their native configuration languages. If Linux and the command line are the foundation, Bash scripting is the layer that turns individual commands into dependable, repeatable systems.

Even teams that eventually adopt more sophisticated tooling, a full CI/CD platform, Terraform for infrastructure, Ansible for configuration, still rely on Bash underneath most of it: a CI job’s “run” step is Bash, a Terraform provisioner frequently calls out to a shell script, and an Ansible task can drop straight into raw shell commands when a built-in module doesn’t cover what’s needed. Skipping Bash to jump straight to more advanced tools tends to backfire; those tools assume the fluency this guide covers.

Frequently Asked Questions

Should I learn Bash or Python first for DevOps automation?

Bash first, for anything that’s mostly running and chaining existing commands (which is most early DevOps automation). Python becomes more valuable once you need real data structures, error handling beyond exit codes, or logic too complex to comfortably express in shell syntax.

Why did my script work when I ran it manually but fail when run by cron or CI?

Almost always an environment difference: cron and CI runners often have a minimal PATH and no shell profile loaded, so commands or variables you assumed were available aren’t. Set the full PATH explicitly and avoid relying on interactive shell configuration inside scripts meant to run unattended.

What’s the difference between sh and bash?

sh is a more minimal POSIX shell standard; bash is a specific, more feature-rich shell that’s a superset of POSIX sh. Scripts using Bash-specific syntax (like arrays or [[ ]] tests) need the #!/bin/bash shebang specifically, not #!/bin/sh.

How do I debug a script that isn’t doing what I expect?

Run it with bash -x script.sh, which prints every command as it executes along with variable substitutions, making it much easier to see exactly where behavior diverges from what you expected.

Are there tools to check a script for common mistakes automatically?

Yes, shellcheck is a widely used static analysis tool that flags unquoted variables, common syntax pitfalls, and portability issues before you ever run the script. It’s worth installing and running against any script before it goes into production use.

Linting Scripts Before They Ship

Most of the pitfalls covered above, unquoted variables, unsafe defaults, portability issues between sh and bash, can be caught automatically before a script ever runs, using shellcheck. It’s a static analysis tool built specifically for shell scripts, and running it as a habit (or as a step in CI before a script gets used in a real pipeline) catches an entire category of bugs before they become a 2am incident.

bash
# Install (Debian/Ubuntu)
sudo apt install shellcheck

# Check a script
shellcheck deploy.sh

# Example output:
# In deploy.sh line 12:
# rm -rf $DIR
#         ^-- SC2115 (info): Use "${DIR:?}" to ensure this never expands to / or empty

Many teams wire shellcheck directly into their CI pipeline so any script committed to the repository is automatically checked on every pull request, the same way a linter would check application code. Given how cheap it is to run and how expensive a silent scripting bug in a production deploy can be, this is one of the highest-value, lowest-effort additions to a team’s DevOps tooling.

If you’re building this skill specifically for a DevOps role, prioritize genuine comfort with the deploy-script pattern shown above (logging, error handling, health checks, rollback) over breadth of Bash trivia. Interviewers and hiring managers care far more about whether you instinctively reach for set -euo pipefail and a real health check than whether you can recite every string manipulation operator Bash supports. Build a handful of small, real scripts, a backup script, a deploy script, a log-cleanup script, and you’ll have covered the patterns that come up constantly in actual DevOps work.

Related reading: continue to Git and GitHub, see CI/CD pipelines for how scripts fit into automated pipelines, or return to the full topics overview.

logo-dark

Lorem ipsum dolor amet consecto adi pisicing elit sed eiusm tempor incidid unt labore dolore.

Add: 70-80 Upper St Norwich NR2
Call: +01 123 5641 231
Email: info@edublink.co

Online Platform

  • About
  • Course
  • Instructor
  • Events
  • Instructor Details
  • Purchase Guide

Links

  • Contact Us
  • Gallery
  • News & Articles
  • FAQ’s
  • Coming Soon

Contacts

Enter your email address to register to our newsletter subscription

Icon-facebook Icon-linkedin2 Icon-instagram Icon-twitter Icon-youtube
Copyright 2026 EduBlink | Developed By DevsBlink. All Rights Reserved
legendarywaysacademy.comlegendarywaysacademy.com

Sign in

Lost your password?

Sign up

Already have an account? Sign in