You are running a Bash script, and you see a syntax error: Unexpected end of file.
What does it mean?
This can happen if you create your script using Windows.
Why?
Because Windows uses a combination of two characters, Carriage Return and Line Feed, as line break in text files (also known as CRLF).
On the other side Unix (or Linux) only use the Line Feed character as line break.
So, let’s see what happens if we save a script using Windows and then we execute it in Linux.
Using the Windows notepad I have created a Bash script called end_of_file.sh:
#/bin/bash
if [ $# -gt 0 ]; then
echo "More than one argument passed"
else
echo "No arguments passed"
fi
And here is the output I get when I execute it:
[ec2-user@localhost scripts]$ ./end_of_file.sh
./end_of_file.sh: line 2: $'r': command not found
./end_of_file.sh: line 8: syntax error: unexpected end of file
How do we see where the problem is?
Edit the script with the vim editor using the -b flag that runs the editor in binary mode:
[ec2-user@localhost scripts]$ vim -b end_of_file.sh
(Below you can see the content of the script)
#/bin/bash^M
^M
if [ $# -gt 0 ]; then^M
echo "More than one argument passed"^M
else^M
echo "No arguments passed"^M
fi^M
At the end of each line we see the ^M character. What is that?
It’s the carriage return we have mentioned before. Used by Windows but not by Unix (Linux) in line breaks.
To solve both errors we need to convert our script into a format that Linux understands.
The most common tool to do that is called dos2unix.
If dos2unix is not present on your system you can use the package manager of your distribution to install it.
For instance, on my server I can use YUM (Yellowdog Updater Modified).
To search for the package I use the yum search command:
[root@localhost ~]$ yum search dos2unix
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
====================== N/S matched: dos2unix =====================================
dos2unix.x86_64 : Text file format converters
And then the yum install command to install it:
[root@localhost ~]$ yum install dos2unix
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
amzn2-core | 2.4 kB 00:00:00
amzn2extra-docker | 1.8 kB 00:00:00
Resolving Dependencies
--> Running transaction check
---> Package dos2unix.x86_64 0:6.0.3-7.amzn2.0.2 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
==================================================================================
Package Arch Version Repository Size
==================================================================================
Installing:
dos2unix x86_64 6.0.3-7.amzn2.0.2 amzn2-core 75 k
Transaction Summary
==================================================================================
Install 1 Package
Total download size: 75 k
Installed size: 194 k
Is this ok [y/d/N]: y
Downloading packages:
dos2unix-6.0.3-7.amzn2.0.2.x86_64.rpm | 75 kB 00:00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : dos2unix-6.0.3-7.amzn2.0.2.x86_64 1/1
Verifying : dos2unix-6.0.3-7.amzn2.0.2.x86_64 1/1
Installed:
dos2unix.x86_64 0:6.0.3-7.amzn2.0.2
Complete!
We are ready to convert our script using dos2unix!
[ec2-user@localhost scripts]$ dos2unix end_of_file.sh
dos2unix: converting file end_of_file.sh to Unix format ...
And now it’s time to execute it:
[ec2-user@localhost scripts]$ ./end_of_file.sh No arguments passed
It works!
If you are interested I have written an article that explains the basics of Bash script arguments.
Conclusion
I have found myself having to use the dos2unix command several times over the years.
And now you know what to do if you see the syntax error “Unexpected end of file” while running a Bash script 🙂
Related FREE Course: Decipher Bash Scripting
Related posts:

I’m a Tech Lead, Software Engineer and Programming Coach. I want to help you in your journey to become a Super Developer!
EOJ needs to be fully left-justified, ie. no leading white-space, and no trailing space either. Also, you could/should (depending on your needs) write the first one as <<'EOJ' .. the quotes disable some shell expansion which can otherwise occur.
From info bash
Here Documents
This type of redirection instructs the shell to read input from the
current source until a line containing only delimiter (with no trailing
blanks) is seen. All of the lines read up to that point are then used
as the standard input for a command.
The format of here-documents is:
<<[-]word
here-document
delimiter
No parameter expansion, command substitution, arithmetic expansion, or
pathname expansion is performed on word. If any characters in word are
quoted, the delimiter is the result of quote removal on word, and the
lines in the here-document are not expanded. If word is unquoted, all
lines of the here-document are subjected to parameter expansion, com‐
mand substitution, and arithmetic expansion. In the latter case, the
character sequence <newline> is ignored, and must be used to quote
the characters , $, and `.
If the redirection operator is <<-, then all leading tab characters are
stripped from input lines and the line containing delimiter. This
allows here-documents within shell scripts to be indented in a natural
fashion.
EOJ needs to be fully left-justified, ie. no leading white-space, and no trailing space either. Also, you could/should (depending on your needs) write the first one as <<'EOJ' .. the quotes disable some shell expansion which can otherwise occur.
From info bash
Here Documents
This type of redirection instructs the shell to read input from the
current source until a line containing only delimiter (with no trailing
blanks) is seen. All of the lines read up to that point are then used
as the standard input for a command.
The format of here-documents is:
<<[-]word
here-document
delimiter
No parameter expansion, command substitution, arithmetic expansion, or
pathname expansion is performed on word. If any characters in word are
quoted, the delimiter is the result of quote removal on word, and the
lines in the here-document are not expanded. If word is unquoted, all
lines of the here-document are subjected to parameter expansion, com‐
mand substitution, and arithmetic expansion. In the latter case, the
character sequence <newline> is ignored, and must be used to quote
the characters , $, and `.
If the redirection operator is <<-, then all leading tab characters are
stripped from input lines and the line containing delimiter. This
allows here-documents within shell scripts to be indented in a natural
fashion.
я смог вырезать и вставить ваш код в файл, и он работал правильно. Если вы
выполните его так, как это должно работать:ваш «file.sh»:
#!/bin/bash # june 2011 if [ $# -lt 3 -o $# -gt 3 ]; then echo "Error... Usage: host database username" exit 0 fiкоманды:
$ ./file.sh arg1 arg2 arg3обратите внимание, что «file.sh» должен быть исполняемым:
$ chmod +x file.shвозможно, вы получаете эту ошибку b / c того, как вы делаете ввод (с трубой, морковью,
так далее.). Вы также можете попробовать разделить условие на два:if [ $# -lt 3 ] || [ $# -gt 3 ]; then echo "Error... Usage: host database username" exit 0 fiили, так как вы используете
bash, вы может использовать встроенный синтаксис:if [[ $# -lt 3 || $# -gt 3 ]]; then echo "Error... Usage: host database username" exit 0 fiи, наконец, вы могли бы, конечно, просто проверить, если 3 аргумента были даны (чистый,
поддерживает совместимость оболочки POSIX):if [ $# -ne 3 ]; then echo "Error... Usage: host database username" exit 0 fi
#!/bin/bash
ocpath='/var/www/nextcloud'
htuser='www-data'
htgroup='www-data'
rootuser='root'
printf "Creating possible missing Directoriesn"
mkdir -p $ocpath/data
mkdir -p $ocpath/assets
mkdir -p $ocpath/updater
printf "chmod Files and Directoriesn"
find ${ocpath}/ -type f -print0 | xargs -0 chmod 0640
find ${ocpath}/ -type d -print0 | xargs -0 chmod 0750
printf "chown Directoriesn"
chown -R ${rootuser}:${htgroup} ${ocpath}/
chown -R ${htuser}:${htgroup} ${ocpath}/apps/
chown -R ${htuser}:${htgroup} ${ocpath}/assets/
chown -R ${htuser}:${htgroup} ${ocpath}/config/
chown -R ${htuser}:${htgroup} ${ocpath}/data/
chown -R ${htuser}:${htgroup} ${ocpath}/themes/
chown -R ${htuser}:${htgroup} ${ocpath}/updater/
chmod +x ${ocpath}/occ
printf "chmod/chown .htaccessn"
if [ -f ${ocpath}/.htaccess ]
then
chmod 0644 ${ocpath}/.htaccess
chown ${rootuser}:${htgroup} ${ocpath}/.htaccess
fi
if [ -f ${ocpath}/data/.htaccess ]
then
chmod 0644 ${ocpath}/data/.htaccess
chown ${rootuser}:${htgroup} ${ocpath}/data/.htaccess
fi
собственно я в баше вообще 0 , даже не знаю с чем его едят , мне просто нужно выполнить файл , а он падло ругается )) , гуглил говорят ошибка чаще всего бывает потому что не закрыт if тегом fi , но у меня походу не тот случай , как решить проблему?
I’m at a loss here.
Kubuntu 18.04.4 LTS
Been running fine for a couple of years.
All of a sudden I get «bash: .bashrc: line 118: syntax error: unexpected end of file» when opening a terminal window.
I haven’t made any modification to this file in ages. I still looked for any missing closing statement, missing quote, etc. I found nothing.
I checked that the end of lines where proper UNIX style, and they were.
Here’s where it gets weird: I ended up copying the original file from /etc/skel to ~/ …with no luck either!
Here’s the content of my current ~/.bashrc (which is like I said the original one from the distrib, that still gives me the same error).
# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
# don't put duplicate lines or lines starting with space in the history.
# See bash(1) for more options
HISTCONTROL=ignoreboth
# append to the history file, don't overwrite it
shopt -s histappend
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=1000
HISTFILESIZE=2000
# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize
# If set, the pattern "**" used in a pathname expansion context will
# match all files and zero or more directories and subdirectories.
#shopt -s globstar
# make less more friendly for non-text input files, see lesspipe(1)
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
debian_chroot=$(cat /etc/debian_chroot)
fi
# set a fancy prompt (non-color, unless we know we "want" color)
case "$TERM" in
xterm-color|*-256color) color_prompt=yes;;
esac
# uncomment for a colored prompt, if the terminal has the capability; turned
# off by default to not distract the user: the focus in a terminal window
# should be on the output of commands, not on the prompt
#force_color_prompt=yes
if [ -n "$force_color_prompt" ]; then
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
# We have color support; assume it's compliant with Ecma-48
# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
# a case would tend to support setf rather than setaf.)
color_prompt=yes
else
color_prompt=
fi
fi
if [ "$color_prompt" = yes ]; then
PS1='${debian_chroot:+($debian_chroot)}[33[01;32m]u@h[33[00m]:[33[01;34m]w[33[00m]$ '
else
PS1='${debian_chroot:+($debian_chroot)}u@h:w$ '
fi
unset color_prompt force_color_prompt
# If this is an xterm set the title to user@host:dir
case "$TERM" in
xterm*|rxvt*)
PS1="[e]0;${debian_chroot:+($debian_chroot)}u@h: wa]$PS1"
;;
*)
;;
esac
# enable color support of ls and also add handy aliases
if [ -x /usr/bin/dircolors ]; then
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
alias ls='ls --color=auto'
#alias dir='dir --color=auto'
#alias vdir='vdir --color=auto'
alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'
fi
# colored GCC warnings and errors
#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
# some more ls aliases
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'
# Add an "alert" alias for long running commands. Use like so:
# sleep 10; alert
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '''s/^s*[0-9]+s*//;s/[;&|]s*alert$//''')"'
# Alias definitions.
# You may want to put all your additions into a separate file like
# ~/.bash_aliases, instead of adding them here directly.
# See /usr/share/doc/bash-doc/examples in the bash-doc package.
if [ -f ~/.bash_aliases ]; then
. ~/.bash_aliases
fi
# enable programmable completion features (you don't need to enable
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc).
if ! shopt -oq posix; then
if [ -f /usr/share/bash-completion/bash_completion ]; then
. /usr/share/bash-completion/bash_completion
elif [ -f /etc/bash_completion ]; then
. /etc/bash_completion
fi
fi
UPDATE:
It’s always a user error, always.
As suggested by @bhordupur I added set -x at the top of my file. I won’t pollute the thread with the output but it allowed me to see that the problem lied in my .bash_aliases (which is called by .bashrc and which I had actually checked too, incidentally). I had defined an alias named fi, if you can believe it. So of course that was interpreted as a closing if statement. Changed the name of the alias. Problem solved.