ia-linux-bash-scripting
/install compound-eng-linux-bash-scripting
Linux Bash Scripting
Produce bash scripts that pass shellcheck --enable=all and shfmt -d with zero warnings.
Target: GNU Bash 4.4+ on Linux. No macOS/BSD workarounds, no Windows paths, no POSIX-only restrictions.
Script Foundation
#!/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\
" "${BASH_SOURCE[0]}" "$LINENO" >&2' ERR
trap 'rm -rf -- "${_tmpdir:-}"' EXIT
-Epropagates ERR traps into functionsinherit_errexitpropagates errexit into$()command substitutions- Always create temp dirs under the EXIT trap:
_tmpdir=$(mktemp -d) - Wrap body in
main() { ... }with source guard:[[ "${BASH_SOURCE[0]}" == "$0" ]] && main "$@"-- enables sourcing for testing
Core Rules
- Quote every expansion:
"$var","$(cmd)","${array[@]}" localfor function variables,local -rfor function constants,readonlyfor script constantsprintf '%s\ 'overecho-- predictable behavior, no flag interpretation[[ ]]for conditionals;(( ))for arithmetic;$()over backticks- End options with
--:rm -rf -- "$path",grep -- "$pattern" "$file" - Require env vars:
: "${VAR:?must be set}" - Never
evaluser input; build commands as arrays:cmd=("grep" "--" "$pat" "$f"); "${cmd[@]}" - Separate
localfrom assignment to preserve exit codes:local val; val=$(cmd) - Debug tracing:
PS4='+${BASH_SOURCE[0]}:${LINENO}: 'withbash -x-- shows file:line per command - Named exit codes:
readonly EX_USAGE=64 EX_CONFIG=78-- no magic numbers inexit - Pipeline diagnostics:
"${PIPESTATUS[@]}"shows exit code of each pipe stage, not just last failure
Safe Iteration
# NUL-delimited file processing
while IFS= read -r -d '' f; do
process "$f"
done \x3C \x3C(find /path -type f -name '*.log' -print0)
# Array from command output
readarray -t lines \x3C \x3C(command)
readarray -d '' files \x3C \x3C(find . -print0)
# Glob with no-match guard
for f in *.txt; do [[ -e "$f" ]] || continue; process "$f"; done
Argument Parsing
verbose=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\
' "$1" >&2; exit 1 ;;
*) break ;;
esac
done
Production Patterns
Dependency check:
require() { command -v "$1" &>/dev/null || { printf 'Missing: %s\
' "$1" >&2; exit 1; }; }
require jq; require curl
Dry-run wrapper:
run() { if [[ "${DRY_RUN:-}" == "1" ]]; then printf '[dry] %s\
' "$*" >&2; else "$@"; fi; }
run cp "$src" "$dst"
Atomic file write -- write to temp, rename into place:
atomic_write() { local tmp; tmp=$(mktemp); cat >"$tmp"; mv -- "$tmp" "$1"; }
generate_config | atomic_write /etc/app/config.yml
Retry with backoff:
retry() { local n=0 max=5 delay=1; until "$@"; do ((++n>=max)) && return 1; sleep $delay; ((delay*=2)); done; }
retry curl -fsSL "$url"
Script locking -- prevent concurrent runs:
exec 9>/var/lock/"${0##*/}".lock
flock -n 9 || { printf 'Already running\
' >&2; exit 1; }
Idempotent operations -- safe to rerun:
ensure_dir() { [[ -d "$1" ]] || mkdir -p -- "$1"; }
ensure_link() { [[ -L "$2" ]] || ln -s -- "$1" "$2"; }
Input validation: [[ "$1" =~ ^[1-9][0-9]*$ ]] || die "Invalid: $1" -- validate at script boundaries with [[ =~ ]]
umask 077for scripts creating sensitive files- Signal cleanup:
trap 'cleanup; exit 130' INT TERM-- preserves correct exit codes for callers
Logging
log() { printf '[%s] [%s] %s\
' "$(date -Iseconds)" "$1" "${*:2}" >&2; }
info() { log INFO "$@"; }
warn() { log WARN "$@"; }
error() { log ERROR "$@"; }
die() { error "$@"; exit 1; }
Anti-Patterns
| Bad | Fix |
|---|---|
for f in $(ls) |
for f in *; do or find -print0 | while read |
local x=$(cmd) |
local x; x=$(cmd) -- preserves exit code |
echo "$data" |
`printf '%s\ |
| ' "$data"` | |
cat file | grep |
grep pat file |
kill -9 $pid first |
kill "$pid" first, -9 as last resort |
cd dir; cmd |
`cd dir |
Performance
- Parameter expansion over externals:
${path%/*}notdirname,${path##*/}notbasename,${var//old/new}notsed (( ))overexpr;[[ =~ ]]overecho | grep- Cache results:
val=$(cmd)once, reuse$val xargs -0 -P "$(nproc)"for parallel workdeclare -A mapfor lookups instead of repeated grep
Bash 4.4+ / 5.x
${var@Q}shell-quoted,${var@U}uppercase,${var@L}lowercasedeclare -n ref=varnamenameref for indirect accesswait -nwait for any background job$EPOCHSECONDS,$EPOCHREALTIME-- timestamps without forkingdate
Linux-Specific
- GNU coreutils differ from macOS:
sed -i(no''suffix),grep -P(PCRE support),readlink -f(canonical path) timeout 30s cmdto prevent automation hangs
ShellCheck
Run shellcheck --enable=all script.sh. Key rules:
- SC2155: Separate declaration from assignment
- SC2086: Double-quote variables
- SC2046: Quote command substitutions
- SC2164:
cd dir || exit - SC2327/SC2328: Use
${BASH_REMATCH[n]}not$nfor regex captures
Pre-commit: shellcheck *.sh && shfmt -i 2 -ci -d *.sh
Verify
Run shellcheck --enable=all and shfmt -d with zero warnings before declaring done. Test edge cases: empty input, missing files, spaces in paths.
- 确保已安装 OpenClaw(本地或 Docker 部署)
- 在对话框中输入安装命令:
/install compound-eng-linux-bash-scripting - 安装完成后,直接呼叫该 Skill 的名称或使用
/compound-eng-linux-bash-scripting触发 - 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
ia-linux-bash-scripting 是什么?
Defensive Bash scripting for Linux: safe foundations, argument parsing, production patterns, ShellCheck compliance. Use when writing bash scripts, shell scri... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 360 次。
如何安装 ia-linux-bash-scripting?
在 OpenClaw 或 Claude Code 对话框中运行命令「/install compound-eng-linux-bash-scripting」即可一键安装,无需额外配置。
ia-linux-bash-scripting 是免费的吗?
是的,ia-linux-bash-scripting 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。
ia-linux-bash-scripting 支持哪些平台?
ia-linux-bash-scripting 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。
谁开发了 ia-linux-bash-scripting?
由 Ilia Alshanetsky(@iliaal)开发并维护,当前版本 v3.0.4。