Loading...
Loading...
Defensive Bash scripting for Linux: safe foundations, argument parsing, production patterns, ShellCheck compliance. Use when writing bash scripts, shell scripts, cron jobs, or CLI tools in bash.
npx skill4agent add iliaal/ai-skills linux-bash-scripting#!/usr/bin/env bash
set -Eeuo pipefail
shopt -s inherit_errexit
readonly SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
trap 'printf "Error at %s:%d\n" "${BASH_SOURCE[0]}" "$LINENO" >&2' ERR
trap 'rm -rf -- "${_tmpdir:-}"' EXIT-Einherit_errexit$()_tmpdir=$(mktemp -d)main() { ... }[[ "${BASH_SOURCE[0]}" == "$0" ]] && main "$@""$var""$(cmd)""${array[@]}"locallocal -rreadonlyprintf '%s\n'echo[[ ]](( ))$()--rm -rf -- "$path"grep -- "$pattern" "$file": "${VAR:?must be set}"evalcmd=("grep" "--" "$pat" "$f"); "${cmd[@]}"locallocal val; val=$(cmd)PS4='+${BASH_SOURCE[0]}:${LINENO}: 'bash -xreadonly EX_USAGE=64 EX_CONFIG=78exit"${PIPESTATUS[@]}"# NUL-delimited file processing
while IFS= read -r -d '' f; do
process "$f"
done < <(find /path -type f -name '*.log' -print0)
# Array from command output
readarray -t lines < <(command)
readarray -d '' files < <(find . -print0)
# Glob with no-match guard
for f in *.txt; do [[ -e "$f" ]] || continue; process "$f"; doneverbose=false; output=""
while [[ $# -gt 0 ]]; do
case "$1" in
-v|--verbose) verbose=true; shift ;;
-o|--output) output="$2"; shift 2 ;;
-h|--help) usage; exit 0 ;;
--) shift; break ;;
-*) printf 'Unknown: %s\n' "$1" >&2; exit 1 ;;
*) break ;;
esac
donerequire() { command -v "$1" &>/dev/null || { printf 'Missing: %s\n' "$1" >&2; exit 1; }; }
require jq; require curlrun() { if [[ "${DRY_RUN:-}" == "1" ]]; then printf '[dry] %s\n' "$*" >&2; else "$@"; fi; }
run cp "$src" "$dst"atomic_write() { local tmp; tmp=$(mktemp); cat >"$tmp"; mv -- "$tmp" "$1"; }
generate_config | atomic_write /etc/app/config.ymlretry() { local n=0 max=5 delay=1; until "$@"; do ((++n>=max)) && return 1; sleep $delay; ((delay*=2)); done; }
retry curl -fsSL "$url"exec 9>/var/lock/"${0##*/}".lock
flock -n 9 || { printf 'Already running\n' >&2; exit 1; }ensure_dir() { [[ -d "$1" ]] || mkdir -p -- "$1"; }
ensure_link() { [[ -L "$2" ]] || ln -s -- "$1" "$2"; }[[ "$1" =~ ^[1-9][0-9]*$ ]] || die "Invalid: $1"[[ =~ ]]umask 077trap 'cleanup; exit 130' INT TERMlog() { printf '[%s] [%s] %s\n' "$(date -Iseconds)" "$1" "${*:2}" >&2; }
info() { log INFO "$@"; }
warn() { log WARN "$@"; }
error() { log ERROR "$@"; }
die() { error "$@"; exit 1; }| Bad | Fix |
|---|---|
| |
| |
| |
| |
| |
| `cd dir |
${path%/*}dirname${path##*/}basename${var//old/new}sed(( ))expr[[ =~ ]]echo | grepval=$(cmd)$valxargs -0 -P "$(nproc)"declare -A map${var@Q}${var@U}${var@L}declare -n ref=varnamewait -n$EPOCHSECONDS$EPOCHREALTIMEdate/proc/self/status/proc/cpuinfo/proc/meminfosystemctljournalctl -u svcsed -i''grep -Preadlink -ftimeout 30s cmdflockapt-get install -ydnf install -ypacman -S --noconfirmshellcheck --enable=all script.shcd dir || exit${BASH_REMATCH[n]}$nshellcheck *.sh && shfmt -i 2 -ci -d *.sh