← Back to list

8 Bash Projects That Actually Help at Work

scripts that quietly make work easier every single day

Obafemi · 2026-05-15 17:34 · 32 claps · 7.5 min read paywalled
#bash-programming #devops-project #devops-practice #bash #devops
Open on Medium ↗
Wiki topics: 💻 · Programming ☁️ · DevOps & Cloud 🔧 · Data Engineering

8 Bash Projects That Actually Help at Work

scripts that quietly make work easier every single day

Bash is still one of the fastest ways to automate repetitive Linux and DevOps tasks.

You do not always need Kubernetes operators, complex Python tooling, or a full monitoring stack to solve a problem. Sometimes a small Bash script is enough to save hours of manual work, speed up debugging, or prevent a bad deployment.

The problem is that many Bash tutorials teach “toy scripts” that nobody uses after the tutorial ends.

This article is different.

These eight projects are designed to be:

  • practical,
  • reusable,
  • beginner-friendly,
  • operationally safer,
  • and realistic enough to use at work.

Each one teaches a useful Bash pattern while solving a real problem engineer could run into every week.

These scripts are intentionally lightweight. They are not replacements for enterprise tooling like Prometheus, Ansible, or Grafana. They are fast utilities you can build in a weekend and keep using for months.

1. Disk Usage Alert Script

One of the most common Linux incidents is simple:

A disk fills up.

When that happens, applications crash, databases stop writing, containers fail, and deployments break.

This script checks mounted filesystems and warns you before storage becomes critical.

Save as disk-watch.sh:

#!/usr/bin/env bash

set -uo pipefail

warn=80
critical=90

usage() {
  echo "Usage: $0 [-w warn_percent] [-c critical_percent]"
}

while getopts ":w:c:h" opt; do
  case "$opt" in
    w) warn="$OPTARG" ;;
    c) critical="$OPTARG" ;;
    h) usage; exit 0 ;;
    *) usage; exit 1 ;;
  esac
done

if ! [[ "$warn" =~ ^[0-9]+$ && "$critical" =~ ^[0-9]+$ ]]; then
  echo "Thresholds must be numbers." >&2
  exit 1
fi

if (( warn >= critical )); then
  echo "Warn threshold must be lower than critical threshold." >&2
  exit 1
fi

status=0

printf "%-25s %-10s %-12s %-10s\n" "FILESYSTEM" "USAGE" "STATUS" "MOUNT"

while read -r fs usage mount; do
  percent="${usage%\%}"

  if (( percent >= critical )); then
    level="CRITICAL"
    status=2
  elif (( percent >= warn )); then
    level="WARN"
    [[ "$status" -lt 1 ]] && status=1
  else
    level="OK"
  fi

  printf "%-25s %-10s %-12s %-10s\n" "$fs" "$usage" "$level" "$mount"

done < <(
  df -P -x tmpfs -x devtmpfs | awk 'NR>1 {print $1, $5, $6}'
)

exit "$status"

Run it:

chmod +x disk-watch.sh
./disk-watch.sh
./disk-watch.sh -w 75 -c 90

This script teaches several useful Bash skills:

  • parsing command output,
  • validating user input,
  • using exit codes correctly,
  • and building CLI tools with options.

It is also genuinely useful.

You can run it:

  • manually,
  • from cron,
  • inside CI jobs,
  • or from a monitoring system.

The important lesson here is not the script itself. It is learning how to turn a repetitive operational check into a reusable command.

2. Fast Log Triage Tool

When systems fail, logs become noisy very quickly.

The problem is not finding logs.

The problem is finding signal inside thousands of lines of noise.

This script scans log files and shows the most repeated error patterns first.

Save as log-triage.sh:

#!/usr/bin/env bash

set -uo pipefail

target="${1:-}"
pattern="${2:-ERROR|FATAL|panic|exception|traceback}"

usage() {
  echo "Usage: $0 <log_file_or_directory> [pattern]"
}

if [[ -z "$target" ]]; then
  usage
  exit 1
fi

if [[ ! -e "$target" ]]; then
  echo "Target not found: $target" >&2
  exit 1
fi

if [[ -d "$target" ]]; then
  mapfile -t files < <(
    find "$target" -type f \
      \( -name "*.log" -o -name "*.out" -o -name "*.txt" \)
  )
else
  files=("$target")
fi

if (( ${#files[@]} == 0 )); then
  echo "No log files found."
  exit 1
fi

tmpfile="$(mktemp)"

grep -hEai "$pattern" "${files[@]}" 2>/dev/null \
  | sed -E '
      s/[0-9]{4}-[0-9]{2}-[0-9]{2}[ T][0-9:\.]+//g;
      s/[[:space:]]+/ /g;
    ' \
  > "$tmpfile"

if [[ ! -s "$tmpfile" ]]; then
  echo "No matching lines found."
  rm -f "$tmpfile"
  exit 0
fi

echo
echo "Most frequent matches:"
echo "======================"

sort "$tmpfile" \
  | uniq -c \
  | sort -nr \
  | head -20

rm -f "$tmpfile"

Run it:

chmod +x log-triage.sh
./log-triage.sh /var/log/nginx/error.log
./log-triage.sh /var/log/myapp "ERROR|WARN|panic"

During incidents, it’s possible to waste time scrolling endlessly through logs.

This script teaches a better approach:

  • group repeated failures,
  • identify patterns quickly,
  • and prioritize the biggest problems first.

You also learn:

  • file discovery with find,
  • regex filtering,
  • temporary file handling,
  • and text processing pipelines.

3. Safer Multi-Server SSH Runner

Running commands across many servers is useful.

It is also dangerous if it’s done carelessly.

This script includes:

  • confirmation prompts,
  • per-host timeouts,
  • command previews,
  • and safer defaults.

Save as ssh-runner.sh:

#!/usr/bin/env bash

set -uo pipefail

hosts_file="${1:-}"
shift || true

usage() {
  echo "Usage: $0 <hosts_file> <command>"
}

if [[ -z "$hosts_file" || $# -eq 0 ]]; then
  usage
  exit 1
fi

if [[ ! -f "$hosts_file" ]]; then
  echo "Hosts file not found." >&2
  exit 1
fi

echo "Command to run:"
echo "----------------"
echo "$*"
echo

read -rp "Continue? [y/N]: " confirm

if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
  echo "Cancelled."
  exit 0
fi

ssh_opts=(
  -o BatchMode=yes
  -o ConnectTimeout=5
  -o ServerAliveInterval=5
  -o ServerAliveCountMax=2
)

success=0
failed=0

while IFS= read -r host; do
  [[ -z "$host" || "$host" =~ ^# ]] && continue

  echo
  echo "===== $host ====="

  if timeout 15 ssh "${ssh_opts[@]}" "$host" "$@"; then
    ((success++))
  else
    echo "FAILED: $host" >&2
    ((failed++))
  fi

done < "$hosts_file"

echo
echo "Finished."
echo "Success: $success"
echo "Failed:  $failed"

(( failed > 0 )) && exit 1

Example hosts.txt:

ubuntu@10.0.0.11
ubuntu@10.0.0.12
ubuntu@10.0.0.13

Run it:

chmod +x ssh-runner.sh
./ssh-runner.sh hosts.txt uptime

This is one of the most practical Bash automation patterns you can learn.

Instead of manually SSH-ing into ten servers, you automate repetitive fleet operations safely.

More importantly, this script teaches an important engineering lesson:

Automation should reduce risk, not increase it.

That is why this script includes:

  • confirmation before execution,
  • connection timeouts,
  • failure tracking,
  • and clear output.

4. Backup Script with Verification

Backups are only useful if they can actually be restored later.

This script creates compressed archives, verifies them, generates checksums, and automatically removes old backups.

Save as backup-dir.sh:

#!/usr/bin/env bash

set -uo pipefail

source_dir="${1:-}"
backup_dir="${2:-./backups}"
retention_days="${3:-7}"

usage() {
  echo "Usage: $0 <source_dir> [backup_dir] [retention_days]"
}

if [[ -z "$source_dir" || ! -d "$source_dir" ]]; then
  usage
  exit 1
fi

mkdir -p "$backup_dir"

timestamp="$(date +%Y%m%d-%H%M%S)"
base_name="$(basename "$source_dir")"

archive="$backup_dir/${base_name}-${timestamp}.tar.gz"

echo "Creating archive..."
tar -czf "$archive" -C "$(dirname "$source_dir")" "$base_name"

echo "Testing archive integrity..."
if ! tar -tzf "$archive" >/dev/null; then
  echo "Archive verification failed." >&2
  exit 1
fi

checksum_file="${archive}.sha256"

sha256sum "$archive" > "$checksum_file"

echo
echo "Backup created:"
echo "$archive"

echo
echo "Checksum file:"
echo "$checksum_file"

echo
echo "Cleaning old backups..."

find "$backup_dir" \
  -type f \
  -name "*.tar.gz" \
  -mtime +"$retention_days" \
  -delete

find "$backup_dir" \
  -type f \
  -name "*.sha256" \
  -mtime +"$retention_days" \
  -delete

Run it:

chmod +x backup-dir.sh
./backup-dir.sh /etc ./backups 14

This project teaches several important operational ideas:

  • archive creation,
  • integrity verification,
  • retention cleanup,
  • and safe filesystem handling.

It also teaches a critical lesson: creating backups is only half the job.

You should also:

  • test restores,
  • keep copies offsite,
  • and protect sensitive backups with encryption.

5. Deployment Preflight Checker

Many deployment failures are predictable.

Missing environment variables, low disk space, or missing dependencies can break releases before the application even starts.

This script catches common problems early.

Save as preflight-check.sh:

#!/usr/bin/env bash

set -uo pipefail

required_cmds=(git curl awk)
required_envs=(APP_NAME DEPLOY_ENV)

min_free_gb="${MIN_FREE_GB:-5}"
target_port="${TARGET_PORT:-8080}"

failures=0

check_command() {
  if command -v "$1" >/dev/null 2>&1; then
    echo "OK: command found -> $1"
  else
    echo "Missing command: $1"
    ((failures++))
  fi
}

check_env() {
  if [[ -n "${!1:-}" ]]; then
    echo "OK: env set -> $1"
  else
    echo "Missing env variable: $1"
    ((failures++))
  fi
}

check_disk() {
  avail=$(df -Pk . | awk 'NR==2 {print int($4/1024/1024)}')

  if (( avail < min_free_gb )); then
    echo "Low disk space."
    ((failures++))
  else
    echo "OK: disk space available"
  fi
}

check_port() {
  if command -v ss >/dev/null 2>&1; then
    if ss -ltn | grep -q ":${target_port} "; then
      echo "Port $target_port already in use."
      ((failures++))
    else
      echo "OK: port available"
    fi
  fi
}

echo "Running preflight checks..."
echo

for cmd in "${required_cmds[@]}"; do
  check_command "$cmd"
done

echo

for env in "${required_envs[@]}"; do
  check_env "$env"
done

echo

check_disk
check_port

echo

if (( failures > 0 )); then
  echo "Preflight failed with $failures issue(s)."
  exit 1
fi

echo "Preflight passed."

Run it:

export APP_NAME=myapp
export DEPLOY_ENV=production

./preflight-check.sh

It’s important to not just automate deployments, but also automate deployment safety checks.

This project teaches:

  • environment validation,
  • dependency checks,
  • operational readiness,
  • and defensive scripting.

That mindset becomes extremely valuable in production environments.

6. Linux Performance Snapshot Collector

When systems become slow, the first challenge is collecting evidence before conditions change again.

This script creates a timestamped troubleshooting snapshot.

Save as perf-snapshot.sh:

#!/usr/bin/env bash

set -uo pipefail

output_dir="${1:-./snapshots}"

mkdir -p "$output_dir"

timestamp="$(date +%Y%m%d-%H%M%S)"
report="$output_dir/perf-$timestamp.txt"

section() {
  title="$1"

  {
    echo
    echo "================================================"
    echo "$title"
    echo "================================================"
  } >> "$report"
}

echo "Created: $(date)" > "$report"

section "UPTIME"
uptime >> "$report" 2>&1

section "MEMORY"
free -h >> "$report" 2>&1

section "DISK"
df -h >> "$report" 2>&1

section "TOP CPU"
ps -eo pid,comm,%cpu,%mem --sort=-%cpu | head >> "$report"

if command -v ss >/dev/null 2>&1; then
  section "SOCKETS"
  ss -s >> "$report"
fi

if command -v vmstat >/dev/null 2>&1; then
  section "VMSTAT"
  vmstat 1 3 >> "$report"
fi

echo
echo "Snapshot saved to:"
echo "$report"

Run it:

chmod +x perf-snapshot.sh
./perf-snapshot.sh

This script teaches an important operational habit:

Capture system state before it changes.

During incidents, engineers often forget critical details because systems recover, restart, or rotate logs before investigation starts.

This project also teaches:

  • report generation,
  • timestamped artifacts,
  • conditional command execution,
  • and safer portability practices.

7. File Integrity Monitor

Instead of pretending to solve full infrastructure drift management, this script focuses on a smaller and more practical problem:

Detecting unexpected file changes.

Save as file-integrity.sh:

#!/usr/bin/env bash

set -uo pipefail

baseline="${BASELINE_FILE:-baseline.sha256}"

usage() {
  echo "Usage:"
  echo "  $0 init <files>"
  echo "  $0 check"
}

cmd="${1:-}"

case "$cmd" in
  init)
    shift

    if (( $# == 0 )); then
      echo "Provide files to track."
      exit 1
    fi

    sha256sum "$@" > "$baseline"

    echo "Baseline created:"
    echo "$baseline"
    ;;

  check)
    if [[ ! -f "$baseline" ]]; then
      echo "Baseline file missing."
      exit 1
    fi

    if sha256sum -c "$baseline"; then
      echo
      echo "Integrity check passed."
    else
      echo
      echo "Integrity check failed."
      exit 1
    fi
    ;;

  *)
    usage
    exit 1
    ;;
esac

Run it:

chmod +x file-integrity.sh

./file-integrity.sh init \
  /etc/ssh/sshd_config \
  /etc/nginx/nginx.conf

./file-integrity.sh check

This teaches a very important concept:

Known-good baselines.

The script itself is intentionally simple, but the underlying idea appears everywhere in security and operations:

  • configuration validation,
  • tamper detection,
  • deployment verification,
  • and compliance monitoring.

8. Daily System Report Generator

Instead of another risky automation tool, this final project creates something many teams actually use:

A lightweight daily system report.

Save as daily-report.sh:

#!/usr/bin/env bash

set -uo pipefail

report_dir="${1:-./reports}"

mkdir -p "$report_dir"

timestamp="$(date +%Y%m%d)"
report="$report_dir/system-report-$timestamp.txt"

{
  echo "System Report"
  echo "Generated: $(date)"
  echo

  echo "Hostname:"
  hostname
  echo

  echo "Uptime:"
  uptime
  echo

  echo "Disk Usage:"
  df -h
  echo

  echo "Memory Usage:"
  free -h
  echo

  echo "Top Processes:"
  ps -eo pid,comm,%cpu,%mem --sort=-%cpu | head
  echo

} > "$report"

echo "Report written to:"
echo "$report"

Run it:

chmod +x daily-report.sh
./daily-report.sh

This project combines many concepts from the earlier scripts:

  • collecting system data,
  • generating reports,
  • timestamping files,
  • and building reusable operational tools.

It is also genuinely useful for:

  • small servers,
  • lab environments,
  • home infrastructure,
  • and learning Linux administration.

[embed]11 Key Linux Performance Tuning Tricks for DevOps Engineers improve application speed, resource usage, and system stability.medium.com

[embed]12 Bash Scripts Every DevOps Engineer Should Automate Let’s dive right into it.blog.devops.dev

Go from a vanilla Ubuntu server to a production-ready baseline in under 10 minutes with the DevOps Starter Kit — a bundle of 20+ Bash scripts, cron jobs, and Docker templates to speed up your infrastructure setup.


메타데이터
post_id
ed755b085dde
slug
8-bash-projects-that-actually-help-at-work-ed755b085dde
url
https://medium.com/@obaff/8-bash-projects-that-actually-help-at-work-ed755b085dde
canonical_url
https://medium.com/@obaff/8-bash-projects-that-actually-help-at-work-ed755b085dde
author_url
https://medium.com/@obaff
status
ok
fetched_at
2026-06-10 08:17:25