Skip to main content
DevOps Insightsguides & answers

Bash · troubleshooting

syntax error: unexpected end of file

Bash reached the end of your script while a block it was reading was still open, so it gave up. Usually an if without its fi, a loop without done, a function without its closing brace, or a quote that never closes; the line it reports is the end of the file, not the mistake.

Reproduced on GNU 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 how it was saved: editors on Windows can add invisible carriage returns.

Run this first

step 1 of 2
bash -n script.sh

Look for The error and, in bash 5, any here-document warning that points at the real line

Checks the syntax without running any command.

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 else does bash -n print?

Cause space

4 of 4 still possible

  • An if, loop, case or function is never closedCommon
  • The script has Windows line endingsCommon
  • A here-document's closing line is indented or has trailing spacesOccasional
  • A quote never closesOccasional

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

    Checks the syntax without running any command.

    Look for The error and, in bash 5, any here-document warning that points at the real line

  2. Step 2

    grep -c $'\r' script.sh

    Counts lines with carriage returns.

    Look for 0 for a script with Unix line endings

Every cause, and how to fix it

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

An if, loop, case or function is never closed

Common

Each if needs fi, each for or while needs done, each case needs esac and each { needs }. One missing anywhere sends bash to the end of the file.

Confirm

bash -n script.sh

The same error without running anything; then count if/fi, do/done and {/} pairs

Fix

  • Add the missing fi, done, esac or }. An editor that folds blocks, or ShellCheck, shows which block is open.

The script has Windows line endings

Common

Saved on Windows or checked out with autocrlf, every line ends in a carriage return, so fi is not fi.

Confirm

grep -c $'\r' script.sh

A number above 0: lines with carriage returns (cat -A on Linux or cat -et on macOS shows them as ^M)

Fix

  • Convert to Unix line endings, for example with sed -i 's/\r$//' script.sh (GNU sed), or your editor's line-ending setting.
  • Keep them out with a .gitattributes line: *.sh text eol=lf.

A here-document's closing line is indented or has trailing spaces

Occasional

The line that ends a here-document must contain only the marker. Indented, or with a space after it, bash never sees it and takes the rest of the file as text, including the fi or done that should have come next.

Confirm

bash -n script.sh 2>&1 | grep 'here-document'

A here-document warning (bash 5) naming the line where it started

Fix

  • Put the closing marker at the very start of its line with nothing after it.
  • To indent the body, use <<-EOF and indent with tabs; <<- strips leading tabs only, and spaces still break it.

A quote never closes

Occasional

An odd number of " or ' characters means the rest of the file is read as one string.

Confirm

bash -n script.sh

unexpected EOF while looking for matching, with the line where the quote opened

Fix

  • Close the quote at the reported line, or escape the quote character if it is meant literally.

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 a block such as if … fi as one unit. If the closing word never arrives, it keeps reading until the file ends and then gives up. That is why the line number points at the end of the file. The real problem is usually higher up: the block that was opened and never closed.

Words used on this page

Here-document
A block of text fed to a command, between <<EOF and a line containing only EOF.
CRLF
Windows line endings: a carriage return (shown as ^M) before each newline. Bash treats it as part of the word.
bash -n
Reads a script and reports syntax errors without running any of it.
What is actually happening

Reproduced with GNU bash 3.2.57 on macOS and GNU bash 5.2.21 on Ubuntu 24.04. A script missing its fi, its done or a function's closing brace stopped with "script.sh: line N: syntax error: unexpected end of file" and exit code 2, where N is one past the last line. Both versions printed the same.

Two causes do not look like missing code. A script saved with Windows line endings failed the same way, because the final fi was really fi followed by a carriage return, which bash does not recognise. And a here-document whose closing EOF line was indented with spaces swallowed the rest of the file, including the fi after it; bash 5.2 first printed a warning that the here-document starting at line 2 was "delimited by end-of-file" because it never found its EOF line, which points straight at the cause.

An unclosed quote is reported differently: "unexpected EOF while looking for matching", followed by the quote character, at the line where the quote opened.

How to tell this is your problem
WhereWhat you see
bashscript.sh: line 12: syntax error: unexpected end of file
bash 5.x, here-documentwarning: here-document at line 4 delimited by end-of-file, naming the EOF marker it wanted
bash, unclosed quoteunexpected EOF while looking for matching, then the quote character

How to know it is actually fixed

  • bash -n script.sh prints nothing and exits 0.

Stopping it happening again

  • Run bash -n (or ShellCheck) on every script in CI.
  • Add *.sh text eol=lf to .gitattributes so Windows checkouts cannot 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