Skip to main content
DevOps Insightsguides & answers

Bash · troubleshooting

syntax error near unexpected token

Bash could not parse the script, so none of it ran, and the token it names is where parsing broke. A token of $'\r' means Windows line endings, ( means unquoted parentheses, and fi or done means a malformed block.

Reproduced on bash 5.2.21, . Where the text says “reproduced”, the behaviour was run on that version, not taken from documentation.

First published

New to this? Read what is actually happening first, then come back to the steps.

On this page · 8 sections

Before you start

  • The script, and the exact token and line number from the error.

Run this first

step 1 of 1
bash -n script.sh

Look for The token and line number

Reports the first syntax error without running anything.

Work out which cause you have

A few questions to narrow the list. Every answer ends in a command that confirms or rules the cause out — this cannot see your cluster, so nothing here is a certainty until you have checked.

Narrow it down

0 answered · nothing is sent anywhere

What is the token in the quotes?

Cause space

4 of 4 still possible

  • The file has Windows line endingsCommon
  • A block is malformedCommon
  • Unquoted parentheses or special charactersOccasional
  • The file is not a shell scriptOccasional

Nothing ruled out yet. Answer the question above and the branches your answer eliminates will strike through here.

Or diagnose it manually

In this order. The first command usually contains the whole answer.

  1. Step 1

    bash -n script.sh

    Reports the first syntax error without running anything.

    Look for The token and line number

Every cause, and how to fix it

Ordered by how often each one turns out to be the answer.

The file has Windows line endings

Common

Edited or checked out on Windows; bash sees do\r, then\r, fi\r as unknown words.

Confirm

cat -v script.sh | head -3

^M at the end of lines

Fix

  • Strip the carriage returns: sed -i 's/\r$//' script.sh (or dos2unix script.sh).
  • Stop them coming back: add *.sh text eol=lf to .gitattributes.
sed -i 's/\r$//' script.sh

Reproduced on Ubuntu 24.04: the same loop then ran.

A block is malformed

Common

An empty then or else, a missing ; or newline before then, do or fi, a missing done or esac.

Confirm

bash -n script.sh

The line and token; check the lines just above it

Fix

  • Give every branch at least one command (: does nothing and is valid).
  • Put then and do on their own line, or after a semicolon: for f in *.txt; do.

Unquoted parentheses or special characters

Occasional

( ) < > | & ; are shell syntax. In text they must be quoted.

Confirm

bash -n script.sh

near unexpected token ( or )

Fix

  • Quote the text: echo "hello (world)".

The file is not a shell script

Occasional

A Python or other script run with bash or sh, or a missing shebang so the wrong interpreter runs it.

Confirm

head -1 script

A shebang for another language, or none at all

Fix

  • Run it with its own interpreter (python3 script.py), and give it the right shebang.

Understanding it properly

Skip this if you are mid-incident — the working part of the page is above. Worth reading afterwards, because understanding the mechanism is what stops the next one.

In plain terms

Bash reads the whole block before running it, and stops at the first word that cannot appear there. The word it quotes is the clue. The line it names is where it noticed, which can be after the real mistake.

Words used on this page

$'\r'
Bash's way of showing a carriage return, the extra character Windows puts at the end of each line.
bash -n
Checks a script's syntax without running it.
What is actually happening

Reproduced on 23 October 2026 with bash 5.2.21 on Ubuntu 24.04. Every case exited 2 and nothing in the file ran, because bash parses before it executes.

With Windows line endings, a plain for loop failed with syntax error near unexpected token $'do\r' (bash wraps the token in a backtick and an apostrophe), and cat -v showed each line ending in ^M. Removing the carriage returns with sed fixed it.

An empty else before fi failed on fi. A for loop missing the ; before do failed on the next command, echo. echo hello (world) failed on (. A Python file run with bash failed on its first string, "hi".

How to tell this is your problem
WhereWhat you see
Windows line endingsscript.sh: line 1: syntax error near unexpected token $'do\r'
Malformed if, for or casescript.sh: line 4: syntax error near unexpected token fi
Unquoted parenthesesscript.sh: line 1: syntax error near unexpected token (

How to know it is actually fixed

  • bash -n script.sh prints nothing, and the script runs.

Stopping it happening again

  • Run bash -n and shellcheck on scripts in CI.
  • Set *.sh text eol=lf in .gitattributes so checkouts on Windows do not add carriage returns.

Sources

Behaviour described here is drawn from official documentation. Where a figure could not be confirmed on an official page it is attributed in the text rather than stated as canonical.

Did this get you to an answer?

No text box on purpose — please do not paste production logs anywhere

Something wrong or out of date? Report it