8 Bash Projects That Actually Help at Work
scripts that quietly make work easier every single day
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]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