Bash 스크립트 보일러플레이트

프로덕션 수준의 Bash 스크립트 템플릿. 옵션 파싱, 로깅, 에러 처리, cleanup 트랩 포함.

Gist
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'

readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly SCRIPT_NAME="$(basename "$0")"

RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'

log_info()  { echo -e "${GREEN}[INFO]${NC}  $(date '+%H:%M:%S') $*"; }
log_warn()  { echo -e "${YELLOW}[WARN]${NC}  $(date '+%H:%M:%S') $*" >&2; }
log_error() { echo -e "${RED}[ERROR]${NC} $(date '+%H:%M:%S') $*" >&2; }
log_debug() { [[ "${VERBOSE:-false}" == true ]] && echo -e "${BLUE}[DEBUG]${NC} $(date '+%H:%M:%S') $*" || true; }

usage() {
  cat <<EOF
Usage: $SCRIPT_NAME [OPTIONS] <argument>

Description:
  Brief description of what this script does.

Options:
  -h, --help       Show this help message and exit
  -v, --verbose    Enable verbose/debug output
  -n, --dry-run    Preview actions without making changes
  -o, --output DIR Output directory (default: ./output)

Arguments:
  argument         Required input argument

Examples:
  $SCRIPT_NAME --verbose myfile.txt
  $SCRIPT_NAME --dry-run --output /tmp myfile.txt
EOF
}

cleanup() {
  local exit_code=$?
  log_debug "Cleanup called (exit: $exit_code)"
  [[ -d "${TMP_DIR:-}" ]] && rm -rf "$TMP_DIR"
}
trap cleanup EXIT

check_deps() {
  local missing=()
  for cmd in curl jq git; do
    command -v "$cmd" &>/dev/null || missing+=("$cmd")
  done
  [[ ${#missing[@]} -gt 0 ]] && { log_error "Missing dependencies: ${missing[*]}"; exit 1; }
}

VERBOSE=false
DRY_RUN=false
OUTPUT_DIR="./output"
POSITIONAL=()

while [[ $# -gt 0 ]]; do
  case $1 in
    -h|--help)    usage; exit 0 ;;
    -v|--verbose) VERBOSE=true; shift ;;
    -n|--dry-run) DRY_RUN=true; shift ;;
    -o|--output)  OUTPUT_DIR="$2"; shift 2 ;;
    -*)           log_error "Unknown option: $1"; usage; exit 1 ;;
    *)            POSITIONAL+=("$1"); shift ;;
  esac
done

[[ ${#POSITIONAL[@]} -lt 1 ]] && { log_error "Missing required argument"; usage; exit 1; }
INPUT="${POSITIONAL[0]}"
TMP_DIR="$(mktemp -d)"

main() {
  check_deps
  log_info "Starting $SCRIPT_NAME"
  log_debug "Input: $INPUT | Output: $OUTPUT_DIR | Dry-run: $DRY_RUN"

  [[ -e "$INPUT" ]] || { log_error "Input not found: $INPUT"; exit 1; }

  if [[ "$DRY_RUN" == true ]]; then
    log_warn "Dry-run mode — no changes will be made"
    return 0
  fi

  mkdir -p "$OUTPUT_DIR"
  log_info "Processing: $INPUT"
  # TODO: add processing logic here
  log_info "Done. Output: $OUTPUT_DIR"
}

main "$@"