DEV Community

Cover image for Advanced Bash Scripting for DevOps Automation (With Copy‑Pasteable Examples)
Sajja Sudhakararao
Sajja Sudhakararao

Posted on

Advanced Bash Scripting for DevOps Automation (With Copy‑Pasteable Examples)

Bash is still the glue that holds a lot of DevOps workflows together. Whether you’re deploying services, wiring health checks into CI, or cleaning up logs on a forgotten VM, a few solid scripting patterns go a very long way.

In this post, you’ll find copy‑pasteable Bash snippets for:

  • Safer script defaults

  • Parameterized deployments

  • Health checks and rollbacks

  • Log rotation and cleanup

  • Simple CPU/memory watchdogs

Everything is written with day‑to‑day DevOps work in mind—not contrived toy examples.


1. Bash foundations that prevent outages

Even experienced engineers skip basics that later cause flaky scripts and silent failures.

#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
Enter fullscreen mode Exit fullscreen mode
  • set -e – exit on the first error instead of continuing in a bad state

  • set -u – fail if a variable is undefined

  • set -o pipefail – make pipelines fail if any command fails

Add a tiny logging helper:

log() { echo "[$(date +'%F %T')] $*"; }
die() { log "ERROR: $*"; exit 1; }
Enter fullscreen mode Exit fullscreen mode

This alone makes every script more observable and safer to reuse across environments.

2. Parameters, flags, and environment‑aware scripts

Hard‑coding values is fine for demos, but production scripts must be configurable.

Use arguments with sensible defaults:

#!/usr/bin/env bash
set -euo pipefail

ENVIRONMENT="${1:-staging}"

log() { echo "[$(date +'%F %T')] [$ENVIRONMENT] $*"; }

log "Deploying to $ENVIRONMENT"
Enter fullscreen mode Exit fullscreen mode

For more control, turn your script into a tiny CLI:

while getopts "e:v:h" opt; do
  case "$opt" in
    e) ENVIRONMENT="$OPTARG" ;;
    v) VERSION="$OPTARG" ;;
    h) echo "Usage: deploy.sh -e <env> -v <version>"; exit 0 ;;
    *) exit 1 ;;
  esac
done
Enter fullscreen mode Exit fullscreen mode

Now teammates and CI pipelines can call the same script with explicit flags.

3. A realistic deployment script pattern

Here’s a trimmed‑down deployment flow you can adapt for your services.

#!/usr/bin/env bash
set -euo pipefail

ENVIRONMENT="${1:-staging}"
APP_DIR="/srv/myapp"
REPO_URL="git@github.com:org/myapp.git"

log() { echo "[$(date +'%F %T')] [$ENVIRONMENT] $*"; }

deploy() {
  log "Updating code..."
  if [[ ! -d "$APP_DIR/.git" ]]; then
    git clone "$REPO_URL" "$APP_DIR"
  fi

  cd "$APP_DIR"
  git fetch --all
  git checkout main
  git pull --ff-only

  log "Installing dependencies..."
  npm ci

  log "Running tests..."
  npm test

  log "Building..."
  npm run build

  log "Restarting service..."
  sudo systemctl restart myapp

  log "Deployment complete."
}

deploy
Enter fullscreen mode Exit fullscreen mode

This pattern is idempotent, easy to wire into CI/CD, and uses systemd for reliable service restarts.

4. Health checks and rollbacks in one script

Automation without safety is just a faster way to ship broken code. Add health checks:

health_check() {
  local url="${1:-http://localhost/health}"
  if curl -fsS "$url" > /dev/null; then
    log "Health check passed for $url"
  else
    die "Health check FAILED for $url"
  fi
}
Enter fullscreen mode Exit fullscreen mode

Then define a simple rollback:

previous_version() {
  git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo ""
}

rollback() {
  local prev
  prev="$(previous_version)"
  [[ -z "$prev" ]] && die "No previous version found for rollback"

  log "Rolling back to $prev"
  git checkout "$prev"
  npm run build
  sudo systemctl restart myapp
}
Enter fullscreen mode Exit fullscreen mode

Wire it together:

deploy
if ! health_check "https://myapp.example.com/health"; then
  log "Health check failed; rolling back"
  rollback
fi
Enter fullscreen mode Exit fullscreen mode

You now have a single script that deploys, validates, and self‑heals.

5. Log rotation and cleanup that actually runs

Not every environment needs a full‑blown logging stack; Bash plus cron still works well.

Compress older logs:

#!/usr/bin/env bash
set -euo pipefail

LOG_DIR="/var/log/myapp"
DAYS_TO_KEEP=7

find "$LOG_DIR" -type f -name "*.log" -mtime +$DAYS_TO_KEEP -print0 \
  | while IFS= read -r -d '' file; do
      gzip "$file"
    done
Enter fullscreen mode Exit fullscreen mode

Remove stale archives:

find "$LOG_DIR" -type f -name "*.gz" -mtime +30 -delete

Schedule it:

30 1 * * * /usr/local/bin/log_cleanup.sh

That’s often enough to keep disks from filling up silently.

6. Lightweight monitoring and alert hooks

You can wrap traditional Linux tools in Bash and push alerts to Slack, email, or a webhook endpoint.

#!/usr/bin/env bash
set -euo pipefail

CPU_THRESHOLD=80
MEM_THRESHOLD=80

cpu_usage() {
  mpstat 1 1 | awk '/Average/ && $12 ~ /[0-9.]+/ {print 100-$12}'
}

mem_usage() {
  free | awk '/Mem:/ {printf("%.0f", $3/$2 * 100)}'
}

CPU=$(cpu_usage)
MEM=$(mem_usage)

if (( CPU > CPU_THRESHOLD || MEM > MEM_THRESHOLD )); then
  echo "High usage detected: CPU=${CPU}% MEM=${MEM}%"
  # TODO: send to Slack / email / webhook here
fi
Enter fullscreen mode Exit fullscreen mode

This is a great complement to Prometheus, Grafana, or hosted solutions.

7. Safer configuration changes

Always pair config edits with backups.

CONFIG="/etc/myapp/config.yaml"
BACKUP="/etc/myapp/config.yaml.$(date +'%F-%H%M%S').bak"

cp "$CONFIG" "$BACKUP"

sed -i 's/feature_x: false/feature_x: true/' "$CONFIG"

systemctl restart myapp
Enter fullscreen mode Exit fullscreen mode

This pattern makes it trivial to revert a bad change during an incident.


If you adapt any of these snippets into your own tooling, drop a comment with your variations—other engineers will benefit from seeing real‑world tweaks. Also, tell which part you’d like to see expanded: deployments, monitoring, or incident tooling.

Top comments (0)