Linux Error Guide: 'syntax error near unexpected token' — Fix Bash Parsing Errors
Fix Bash 'syntax error near unexpected token' errors: handle arrays, subshells, function syntax, stray parentheses, and running a bash script under sh instead of bash.
- #linux
- #troubleshooting
- #errors
- #bash
Stuck on this Linux Admins error? Get the free incident triage checklist
A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.
Overview
Bash raises this the moment it reads a token it can’t make sense of in the current context. The token it names is the first thing that didn’t fit, and it’s usually right at or just before the reported point:
$ ./setup.sh
./setup.sh: line 12: syntax error near unexpected token '('
$ echo "hi" )
bash: syntax error near unexpected token ')'
Unlike unexpected end of file (which means something was left open), near unexpected token means Bash hit a character — most often (, ), {, }, ;;, &&, |, newline, or fi/then/do in the wrong place — that isn’t valid where it appeared. The single most common real-world cause is running a script written for Bash with sh, where Bash-only syntax like arrays and (( )) isn’t understood.
Symptoms
syntax error near unexpected token '('when declaring arrays or defining functions.syntax error near unexpected token ')'from a subshell or misplaced paren.syntax error near unexpected token 'newline'or';;'inside acasestatement.syntax error near unexpected token 'fi'/'then'/'done'from a missing separator like;.- The script runs with
bash script.shbut fails withsh script.shor./script.sh(wrong shebang).
Common Root Causes
- Run under
sh, notbash— POSIXsh(dash on Debian/Ubuntu) rejects Bash arraysa=( ),[[ ]], and(( )). - Array syntax mistakes — a space or quoting problem in
arr=( a b c ), or indexing likearr[0]=xundersh. - Function definition errors — mixing
function foo {styles wrong, orfoo () {with a stray token. - Unescaped parentheses — literal
(in acasepattern,testexpression, or string without quoting or escaping. - Missing command separator —
if [ x ] thenwithout;beforethen, sothenis “unexpected.” - Copy-paste artifacts — smart quotes, non-breaking spaces, or CRLF endings that Bash reads as unexpected tokens.
Diagnostic Workflow
First check the shebang and how the script is actually being invoked — this resolves a large share of cases:
head -1 setup.sh # expect #!/usr/bin/env bash or #!/bin/bash
grep -n 'setup.sh' /path/to/caller # is something calling it with 'sh setup.sh'?
Run a parse-only check to localize the token without executing side effects:
bash -n setup.sh # syntax check; reports the exact line
shellcheck setup.sh # explains array/subshell/function mistakes precisely
Reproduce the sh-vs-bash difference directly — if it passes under bash but fails under sh, the syntax is Bash-only:
bash -n setup.sh && echo "bash: OK"
sh -n setup.sh || echo "sh: FAILS -> needs bash"
Hunt for invisible characters that masquerade as tokens:
cat -A setup.sh | sed -n '10,14p' # ^M = CR, M-BM- = non-breaking space, $ = line end
file setup.sh # detect CRLF line endings
Example Root Cause Analysis
A provisioning script worked on a developer laptop but failed in a CI container:
$ sh deploy.sh
deploy.sh: line 8: syntax error near unexpected token '('
Line 8 declared a Bash array:
SERVERS=( web1 web2 web3 )
The developer ran it with ./deploy.sh (which used the #!/bin/bash shebang and worked), but the CI step explicitly invoked sh deploy.sh. On Debian-based images sh is dash, which has no array support, so SERVERS=( ... ) is a syntax error at the (. Confirming with both shells proved it:
$ bash -n deploy.sh && echo OK # OK
$ sh -n deploy.sh # syntax error near unexpected token '('
The fix was to invoke the script with Bash consistently — changing the CI step from sh deploy.sh to bash deploy.sh (or ./deploy.sh, honoring the shebang). Where POSIX portability was required instead, the alternative was rewriting the array as space-separated words or set -- positional parameters.
Prevention Best Practices
- Match the interpreter to the syntax: keep a
#!/usr/bin/env bashshebang and always run Bash scripts withbash/./, neversh. - Run
shellcheckandbash -nin CI so token errors are caught before deploy. - Add a separator before block keywords:
if [ x ]; then,for i in ...; do. - Quote or escape literal parentheses, and write arrays and
[[ ]]/(( ))only in Bash scripts. - Enforce LF endings and reject smart quotes/non-breaking spaces via editor config and
cat -Aspot checks. - Use
command -v shellcheckin a pre-commit hook to block scripts that fail static analysis.
Quick Command Reference
head -1 script.sh # verify the shebang
bash -n script.sh # syntax check under bash
sh -n script.sh # does it fail under POSIX sh?
shellcheck script.sh # explain the offending token
cat -A script.sh # reveal CR (^M) and NBSP characters
file script.sh # detect CRLF line endings
bash script.sh # run with bash, not sh
Conclusion
syntax error near unexpected token means Bash hit a character it can’t interpret where it appears — commonly a ( from array or subshell syntax, a stray paren, or a missing ; before then/do. Before combing the code, confirm the script is actually running under bash and not sh, since Bash-only constructs are the number-one cause. Then let bash -n and shellcheck name the exact line and token, and rule out invisible CRLF or smart-quote characters. Matching interpreter to syntax resolves most of these instantly.
Fixed it? Get 500 Linux Admins & DevOps AI prompts — free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.
Did this fix your issue?
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.