Skip to content

/errors/bash/syntax-error-near-unexpected-token

bash: syntax error near unexpected token

verified onenvironmentlocal · linux 6.18.44-fc-v140 x64 · GNU bash 5.2.21updated
tool
Bash
exit code
2
versions
bash 4.x – 5.x
os
linux, macos, windows

syntax error near unexpected token means bash's parser hit a word or symbol that is not allowed at that position, so it refused to run the script. The token in backquotes is where parsing failed; the real mistake is usually just before it (a missing then, do or ;, or an unquoted parenthesis). Scripts edited on Windows often fail this way because of CRLF line endings.

Reproduce it

bash
printf 'if [ -f /etc/hostname ]\necho found\nfi\n' > missing_then.sh
bash missing_then.sh

Output · exit 2

missing_then.sh: line 3: syntax error near unexpected token `fi'
missing_then.sh: line 3: `fi'

then is missing, so bash reaches fi while it still expects the then part. The exit status of a syntax error is 2.

Unquoted parentheses

bash
echo 'echo Total (incl. tax)' > parens.sh
bash parens.sh

Output · exit 2

parens.sh: line 1: syntax error near unexpected token `('
parens.sh: line 1: `echo Total (incl. tax)'

( starts a subshell in bash. Quote the text: echo 'Total (incl. tax)'.

Windows line endings (CRLF)

A script saved with CRLF line endings has an invisible carriage return (\r, shown by bash as $'\r') at the end of every line. On Linux and macOS bash reads it as part of the word, so do, then or { is not recognised as a keyword and the script fails with this error or with $'\r': command not found. Git Bash on Windows tolerates CRLF scripts, which is why a script can work locally and fail in a Linux CI job. Count and strip the carriage returns:

bash
printf 'for f in a b; do\r\n  echo "$f"\r\ndone\r\n' > crlf.sh
printf 'carriage returns: %s\n' "$(tr -cd '\r' < crlf.sh | wc -c)"
tr -d '\r' < crlf.sh > lf.sh
printf 'carriage returns: %s\n' "$(tr -cd '\r' < lf.sh | wc -c)"
bash lf.sh

Output

carriage returns: 3
carriage returns: 0
a
b

dos2unix script.sh (or sed -i 's/\r$//' script.sh with GNU sed on Linux) converts the file in place. In Git, a .gitattributes line *.sh text eol=lf keeps shell scripts LF on every platform (see core.autocrlf).

Check without running

bash
printf 'while true\necho loop\ndone\n' > loop.sh
bash -n loop.sh

Output · exit 2

loop.sh: line 3: syntax error near unexpected token `done'
loop.sh: line 3: `done'

bash -n parses the file and reports syntax errors without executing anything. ShellCheck explains many of these errors in more detail.

Sources