11ai bash troubleshooting
Separate observed facts from theories. Get the exact error text, the exit status, and the interpreter that actually ran, then identify which layer failed before changing anything. Do not add || true, remove set -e, or loosen quoting to make a symptom disappear — each hides the failure rather than fixing it.
Evidence collection
bash --version | head -1
head -1 script.sh
ls -la script.sh
bash -n script.sh
shellcheck script.sh
bash -x script.sh ARGS 2>&1 | tail -40
./script.sh ARGS; echo "exit: $?"
bash -x traces each expanded command before running it, which is the single most useful tool here: it shows what a variable actually held, not what it was supposed to hold. For a long script, narrow the trace:
set -x
suspect_section
set +x
PS4='+ ${BASH_SOURCE##*/}:${LINENO}: ' bash -x script.sh 2>&1 | tail -40
That PS4 adds the file and line number to every traced line, which turns a wall of output into a location.
Trace output includes expanded variable values, so it can print tokens and connection strings. Redact before quoting it, and never paste a full trace of a script that handles credentials.
Capture the exit status and the pipeline stages separately:
command1 | command2; echo "${PIPESTATUS[@]}"
Classify the failure
syntax error near unexpected token, orbad substitution— the interpreter is not the one you think. Read the shebang and the version. A#!/bin/shscript getsdashon many systems and Bash 3.2 on macOS, neither of which has[[ ]]with regex, associative arrays, or${var^^}. This is an interpreter problem, not a syntax problem.unbound variable—set -udoing its job. The variable is genuinely unset, usually a typo or a missing argument. Fix the source; do not remove-u. For a legitimately optional variable use"${var:-}".- Wrong behaviour with a filename containing a space — an unquoted expansion word-split.
shellchecknames the line. Quote it and pairfind -print0withread -d ''. - A pipeline reports success but produced nothing — no
pipefail, so only the last command's status was seen. Addset -o pipefailand readPIPESTATUS. command not foundin a script but the command works in the terminal — the script did not read~/.bashrc, so aPATHaddition or a function defined there does not exist. Aliases never work in non-interactive shells. SetPATHin the script or use an absolute path.permission deniedrunning the script — the file is not executable.chmod +x. If it is executable, the interpreter in the shebang may not exist.bad interpreter: no such file or directoryon a shebang that looks right — Windows line endings. The\rbecomes part of the interpreter path. Confirm withhead -1 script.sh | cat -Aand fix withtr -d '\r'.- A script hangs with no output — something is waiting on standard input. A
readwith no input, ansshat a password prompt, or a command expecting a terminal. Add</dev/nullto identify it, andBatchMode=yesforssh. - A script continues past a failure —
set -edoes not fire inside a condition, on the left of&&or||, or inlocal var="$(cmd)". Split the assignment from the declaration. - An
EXITtrap did not clean up — the trap was registered after the failure point, or the process was killed withSIGKILL, which cannot be trapped. - Exit
137— killed bySIGKILL, almost always out of memory. Exit124is atimeoutexpiry,126not executable,127not found,130user interrupt. - Works locally, fails in cron — cron runs with a minimal environment, no
~/.bashrc, a different working directory, and no terminal. SetPATHexplicitly, use absolute paths,cdat the top, and redirect output to a log. - Different sort order or case behaviour between machines — locale. Set
LC_ALL=Cwhere the result must be reproducible.
Remediation discipline
- Reproduce with the smallest failing command, in the same interpreter and environment as the failure. A bug that only appears in cron must be reproduced there or with
env -i. - Run
shellcheckbefore hand-reading the script. It finds the quoting and splitting classes by inspection. - Fix the cause, not the symptom. Adding
|| true, removingset -euo pipefail, or unquoting an expansion makes the script report success while doing the wrong thing. - Make one change, then rerun the original failing invocation.
- State confidence as high, medium, or low and name the evidence you are missing.
- Before rerunning a script that writes or deletes, check what the failed run already did. A script that failed halfway may have left partial state, and rerunning it can double-apply.
Hand off when the cause is elsewhere: a missing or old Bash to 11ai-operator-bash-setup, an environment or PATH question to 11ai-operator-bash-environment, a restructure to 11ai-operator-bash-scripting, and adding coverage so the bug cannot return to 11ai-operator-bash-testing.
Report
Conclude with: the interpreter and version that ran, the exact error text and exit status, the traced line where it failed, the root cause or remaining uncertainty, the fix applied or proposed and why it addresses the cause rather than the symptom, any partial state the failed run left behind, and the verification result. Redact credentials from trace output.