Bash "Syntax Error Near Unexpected Token" — and the Windows Line-Ending Trap

Bash rejects the script at parse time. Half the cases are quoting/paren mistakes; the sneaky other half are CRLF line endings from Windows editors that make valid code unparseable on Linux.

What you'll see

Root causes

CRLF line endings (the classic)

Windows-saved scripts carry \r. Bash sees 'then\r' as a different token. cat -A file | grep -c '\^M\$' detects it; dos2unix or sed -i 's/\r$//' fixes it.

Quoting/structure mistakes

Unquoted ( ) | < > in test contexts, a missing then/fi/done, or a function defined where bash expects a command. bash -n file parses without running — fastest loop for finding them.

Fix it

  1. Check line endings first (free fix, half the cases)
    cat -A script.sh | head -5   # '^M$' at line ends = CRLF; then: sed -i 's/\r$//' script.sh
  2. Syntax-check without executing
    bash -n script.sh   # pinpoints the first parse error line
  3. Fix quoting around special characters
    # wrap in quotes: grep "foo(bar)" — unquoted parens are subshell syntax to bash
  4. Prevent recurrence: editor + git settings
    git config core.autocrlf input   # and .gitattributes: *.sh text eol=lf

Field note

ShellCheck finds not just this error but ten future ones: install it, run sh check.sh script.sh. Shebang mismatch (sh vs bash) changes the grammar: sh on Debian is dash, stricter than bash.

Common questions

Why does the script work locally but fail in CI?

Line endings: your Windows/macOS editor saved CRLF, and CI's Linux shell chokes. Fix with dos2unix or the .gitattributes rule, then verify with cat -A.

Bash says the error is on line 1 but that line looks fine?

Often the error is a CR at the end of a control keyword ('then\r') — bash reports the token, not the invisible character. cat -A exposes the ^M immediately.

Ship it right the first time

Our most-documented failures, packaged as ready-to-ship starter kits: Docker, Kubernetes, and Terraform.

Browse the template store →

One-time. Yours to modify. Instant download from the NinjaOps template store.