Bash script boilerplate
Boilerplate for starting bash scripts.
Code
#!/usr/bin/env bash
# -*- coding: utf-8 -*-
# shellcheck disable=SC2155,SC2312
#
# Script: myscript.sh
# Purpose: Short description of what this script does.
# Usage: myscript.sh [-h] [-v] [-n] -i <input> [-o <output>]
# Example: myscript.sh -v -i data.txt -o out.bin
# Requires: bash >= 4, coreutils
set -Eeuo pipefail
IFS=$'\n\t'
# --------------- config (edit me) ----------------
VERSION="0.1.0"
REQ_CMDS=(awk sed grep mktemp)
# -------------------------------------------------
# Colors (auto-disabled if not a tty)
if [[ -t 1 ]]; then
BOLD=$'\e[1m'; RED=$'\e[31m'; YELLOW=$'\e[33m'; BLUE=$'\e[34m'; RESET=$'\e[0m'
else
BOLD=""; RED=""; YELLOW=""; BLUE=""; RESET=""
fi
# Logging helpers
log() { printf '%s\n' "$*"; }
info() { printf '%sINFO:%s %s\n' "$BLUE" "$RESET" "$*"; }
warn() { printf '%sWARN:%s %s\n' "$YELLOW" "$RESET" "$*" >&2; }
err() { printf '%sERROR:%s %s\n' "$RED" "$RESET" "$*" >&2; }
die() { err "$*"; exit 1; }
# Cleanup (runs on EXIT)
_tmp_dir=""
cleanup() {
local ec=$?
[[ -n "${_tmp_dir:-}" && -d "$_tmp_dir" ]] && rm -rf -- "$_tmp_dir"
exit "$ec"
}
trap cleanup EXIT
# Better error messages (runs on ERR)
on_err() {
local ec=$? line=${BASH_LINENO[0]} cmd=${BASH_COMMAND}
err "Command failed (exit $ec) at line $line: ${BOLD}${cmd}${RESET}"
}
trap on_err ERR
usage() {
cat <<EOF
${BOLD}Usage:${RESET} $(basename "$0") [options]
Options:
-i FILE Input file (required)
-o FILE Output file (default: stdout)
-n Dry-run (show actions, don't change anything)
-v Verbose logging
-h Show this help and exit
--version Print version and exit
Examples:
$(basename "$0") -i in.txt -o out.bin
EOF
}
version() { echo "$(basename "$0") v$VERSION"; }
check_deps() {
for c in "${REQ_CMDS[@]}"; do
command -v "$c" >/dev/null 2>&1 || die "Missing required command: $c"
done
}
# Globals set by flags
INPUT=""
OUTPUT=""
DRYRUN=0
VERBOSE=0
# Parse args (short flags via getopts; handle --version manually)
if [[ "${1:-}" == "--version" ]]; then version; exit 0; fi
while getopts ":i:o:nvh" opt; do
case "$opt" in
i) INPUT=$OPTARG ;;
o) OUTPUT=$OPTARG ;;
n) DRYRUN=1 ;;
v) VERBOSE=1 ;;
h) usage; exit 0 ;;
\?) die "Unknown option: -$OPTARG";;
:) die "Option -$OPTARG requires an argument";;
esac
done
shift $((OPTIND - 1))
# Validate args
[[ -z "$INPUT" ]] && { usage; die "Missing required -i FILE"; }
[[ ! -r "$INPUT" ]] && die "Input not readable: $INPUT"
# Prepare environment
check_deps
_tmp_dir="$(mktemp -d -t "$(basename "$0")".XXXXXX)"
[[ $VERBOSE -eq 1 ]] && info "Temp dir: $_tmp_dir"
# Helper to run commands respecting dry-run
run() {
[[ $VERBOSE -eq 1 ]] && info "RUN: $*"
if [[ $DRYRUN -eq 1 ]]; then
printf '[dry-run] %s\n' "$*"
else
eval "$@"
fi
}
main() {
info "Starting $(basename "$0")"
[[ $VERBOSE -eq 1 ]] && set -x
# ---- your logic here ----
# Example: transform input to output (or stdout)
if [[ -n "${OUTPUT:-}" ]]; then
run "awk '{print NR \":\" \$0}' \"$INPUT\" > \"$OUTPUT\""
info "Wrote: $OUTPUT"
else
run "awk '{print NR \":\" \$0}' \"$INPUT\""
fi
# -------------------------
info "Done."
}
main "$@"