here document - unexpected end of file [duplicate] - bash

This question already has answers here:
here-document gives 'unexpected end of file' error
(10 answers)
Closed 6 years ago.
I have been trying to run the following script from the book Linux Command Line, but am getting an error unexpected end of file. I incrementally filled in each function and it seems like the issue is with the function report_home_space(). The script looks okay to me, though.
Any idea where the issue lies?
#!/bin/bash
# Program to output a system information page
declare -r TITLE="System Information Report for $HOSTNAME"
declare -r CURRENT_TIME=$(date)
declare -r TIMESTAMP="Generated $CURRENT_TIME, by $USER"
report_uptime(){
cat <<- _EOF_
<H2>System Uptime</H2>
<PRE>$(uptime)</PRE>
_EOF_
return
}
report_disk_space(){
cat <<- _EOF_
<H2>Disk Space Utilization</H2>
<PRE>$(df -h)</PRE>
_EOF_
return
}
report_home_space(){
cat <<- _EOF_
<H2>Home Space Utilization</H2>
<PRE>$(du -sh ~/*)</PRE>
_EOF_
return
}
cat << _EOF_
<HTML>
<HEAD>
<TITLE>$TITLE</TITLE>
</HEAD>
<BODY>
<H1>$TITLE</H1>
<P>$TIMESTAMP</P>
$(report_uptime)
$(report_disk_space)
$(report_home_space)
</BODY>
</HTML>
_EOF_

The <<- form of here documents are very sensitive to leading whitespace. They only allow for tabs. If you accidentally used leading space or your editor expands tabs automatically, the here document would never find its closing token, and that would account for the error you see.
If you want to maintain your indentation, but want an alternative to the <<- notation, consider just using echo or printf, like so:
report() {
printf '<H2>%s</H2>\n<PRE>%s</PRE>\n' "$1" "$2"
}
report_home_space() {
report 'Home Space Utilization' "$(du -sh ~/*)"
}
# Other reports as above...

Related

Syntax error: end of file unexpected (expecting "}")

I am running the following script within a longer html file
report_home_space () {
cat <<- _EOF_
<h2>Home Space Utilization</h2>
<pre>$(du -sh /home/*)</pre>
_EOF_
return
}
cat <<- _EOF_
<html>
*
other html here
*
</html>
_EOF_
Why I am getting end of file unexpected what should I be supposed to do here ?
I have also tried cat << EOF but it does not work within my functions, the problem arises only when I insert Here Document inside a function. (I am currently using the bash shell)
If you are going to indent the here-doc delimiter, it must be with tab characters. In your code, everything until the last line of the script is part of the first here-doc.
report_home_space () {
cat <<- _EOF_
<h2>Home Space Utilization</h2>
<pre>$(du -sh /home/*)</pre>
_EOF_
return
}
Here, the 8 spaces used to indent the two lines of the here document and the terminator should be replaced with a literal tab character.
Put the return statement after the closing brace
}
return
cat <<- _EOF_
<html>

syntax error: unexpected end of file when editing code within here documents with emacs. working fine with nano

my sys_info_script as edited with emacs:
#!/bin/bash
# Program to output a system information page
declare -r TITLE="System Information Report For $HOSTNAME"
declare -r CURRENT_TIME="$(date +"%x %r %Z")"
declare -r TIMESTAMP="Generated $CURRENT_TIME, by $USER"
function report_uptime {
cat <<- _EOF_
<h2>System Uptime</h2>
<pre>$(uptime)</pre>
_EOF_
return
}
function report_disk_space {
cat <<- _EOF_
<h2>Disk Space Utilization</h2>
<pre>$(df -h)</pre>
_EOF_
return
}
function report_home_space {
cat <<- _EOF_
<h2>Home Space Utilization</h2>
<pre>$(du -sh /home/*)</pre>
_EOF_
return
}
cat << _EOF_
<html>
<head>
<title>$TITLE</title>
</head>
<body>
<h1>$TITLE</h1>
<p>$TIMESTAMP</p>
$(report_uptime)
$(report_disk_space)
$(report_home_space)
</body>
</html>
_EOF_
when i execute the script if get an unexpected end of file `syntax-error
the same file as edited by nano:
#!/bin/bash
# Program to output a system information page
declare -r TITLE="System Information Report For $HOSTNAME"
declare -r CURRENT_TIME="$(date +"%x %r %Z")"
declare -r TIMESTAMP="Generated $CURRENT_TIME, by $USER"
function report_uptime {
cat <<- _EOF_
<h2>System Uptime</h2>
<pre>$(uptime)</pre>
_EOF_
return
}
function report_disk_space {
cat <<- _EOF_
<h2>Disk Space Utilization</h2>
<pre>$(df -h)</pre>
_EOF_
return
}
function report_home_space {
cat <<- _EOF_
<h2>Home Space Utilization</h2>
<pre>$(du -sh /home/*)</pre>
_EOF_
return
}
cat << _EOF_
<html>
<head>
<title>$TITLE</title>
</head>
<body>
<h1>$TITLE</h1>
<p>$TIMESTAMP</p>
$(report_uptime)
$(report_disk_space)
$(report_home_space)
</body>
</html>
_EOF_
this one runs fine
the sdiff results on the cat -A of the two file (< emacs-edit and > nano-edit):
As you can see emacs's default space-indentation behavior is probably causing the trouble within here documents.
I'd like to continue to use emacs to edit shell scripts with here documents. How do I fix this issue?
Thanks!
Per the bash manual regarding here docs,
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.
You must therefore ensure that only tabs are used for such
indentation, as bash does not support spaces for indentation in this
situation.
The buffer-local indent-tabs-mode variable controls whether or not
Emacs will use tabs in indentation, and then you also need to ensure
that the buffer-local tab-width aligns with (in this case)
sh-basic-offset so that your indentation will only be tabs, and not
a mixture of tabs and spaces.
See also M-x customize-group RET sh-indentation RET
These could potentially be set as file-local variables, to ensure that other Emacs users wouldn't accidentally break this formatting.

Inherit indentation when using cat in bash function to print multiple lines

In the middle of doing cat <<, if we invoke a bash function that uses cat << as well, the indentation is only inherited for the first line.
This is better explained using a simple example script:
#!/bin/bash
write_multiple_lines() {
cat <<_EOF_
<h1>Header</h1>
<p>Paragraph</p>
_EOF_
return
}
cat << _EOF_
<html>
$(write_multiple_lines)
</html>
_EOF_
The result is as follows (the <p> doesn't follow <h1>'s indentation).
<html>
<h1>Header</h1>
<p>Paragraph</p>
</html>
while the desired result is
<html>
<h1>Header</h1>
<p>Paragraph</p>
</html>
I was expecting the indentation would be inherited if cat << is used. Is there any workaround for this (other than manually adding indentation to subsequent lines as pointed out by #bob dylan in the comment)?
The only way to 'preserve' it is to change your input file. The reason why <p> is indented is because you've indented it here:
$(write_multiple_lines)
Since you don't want to change your input e.g.
write_multiple_lines() {
cat <<_EOF_
<h1>Header</h1>
<p>Paragraph</p>
_EOF_
return
}
You could change it to echo the spaces for you and then print each line e.g.
#!/bin/bash
write_multiple_lines() {
while read p; do
echo " " "$p"
done <<_EOF_
<h1>Header</h1>
<p>Paragraph</p>
_EOF_
return
}
cat << _EOF_
<html>
$(write_multiple_lines)
</html>
_EOF_
output:
<html>
<h1>Header</h1>
<p>Paragraph</p>
</html>
Though this is less dynamic / obvious then if you formatted it verbatim so I'd stick by my original suggestion before doing something like this.

Some of my here doc delimiters in bash script getting skipped

Very new to scripting. Working my way through "The Linux Command Line" by Shotts.
I keep running into an issue with some of the here doc delimiters being skipped.
I have report_uptime and report_disk_space commented out currently, but when I uncomment them some of my Here doc delimiters are being skipped.
Am I just missing something blaringly obvious breaking the script, or am I jacking up the here docs somehow?
#!/bin/bash
# Program to output a system information page
##### Constants
TITLE="System Information Report For $HOSTNAME"
CURRENT_TIME=$(date +"%x %r %Z")
TIME_STAMP="Generated $CURRENT_TIME, by $USER"
##### Functions
report_uptime () {
cat <<- _EOF_
<H2>System Uptime</H2>
<PRE>$(uptime)</PRE>
_EOF_
return
}
#report_disk_space () {
# cat <<- _EOF_
# <H2>Disk Space Utilization</H2>
# <PRE>$(df -h)</PRE>
# _EOF_
# return
#}
#report_home_space () {
# cat <<- _EOF_
# <H2>Home Space Utilization</H2>
# <PRE>$(du -sh /home/*)</PRE>
# _EOF_
# return
#}
##### HTML code
cat << _EOF_
<HTML>
<HEAD>
<TITLE>$TITLE</TITLE>
</HEAD>
<BODY>
<H1>$TITLE</H1>
<P>$TIME_STAMP</P>
$(report_uptime)
$(report_disk_space)
$(report_home_space)
</BODY>
</HTML>
_EOF_
The Bash man page says this of here documents (emphasis added):
This type of redirection instructs the shell to read input from the current source until a line containing only [the 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.
[...]
If the redirection operator is <<-, then all leading tab characters are stripped from input lines and the line containing [the delimiter].
I reviewed the literal whitespace in your code by opening the question for editing. Supposing that the code presented accurately reflects your actual script, including whitespace, your problem is trailing spaces on the lines containing your here documents' closing delimiters.

bash functions returns "command not found"

I've been trying to get this function to work without returning errors, but so far I'm unable to figure out what the problems is. I'm using $(report_home_space) to insert the contents of the functions on a small bit of hmtl but keep getting the error: report_home_space: command not found on line 30.
report_home_space () {
cat <<- _EOF_
<H2>Home Space Utilization</H2>
<PRE>$(du -sh /home/*)</PRE>
_EOF_
}
I'm new to shell scripting, but I can't not find anything wrong with the syntax of the function, and the spelling seems correct. Thanks in advance.
Full script is:
#!/bin/bash
# Program to output a system information page
TITLE="System Information Report For $HOSTNAME"
CURRENT_TIME=$(date +"%x %r %z")
TIMESTAMP="Generated $CURRENT_TIME, by $USER"
report_uptime () {
cat <<- _EOF_
<H2>system Uptime</H2>
<PRE>$(uptime)</PRE>
_EOF_
}
report_disk_space () {
cat <<- _EOF_
<H2>Disk Space Ulitilizatoin</H2>
<PRE>$(df -h)</PRE>
_EOF_
}
report_home_space () {
cat <<- _EOF_
<H2>Home Space Utilization</H2>
<PRE>$(du -sh /home/*)</PRE>
_EOF_
}
cat << _EOF_
<HTML>
<HEAD>
<TITLE>$TITLE</TITLE>
<BODY>
<H1>$TITLE</H1>
<P>$TIMESTAMP</P>
$(report_uptime)
$(report_disk_space)
$(report_home_space)
</BODY>
<HTML>
_EOF_
BTW, your script works fine. Did you by any chance type it up in a Windows environment before uploading to a UNIX env?
Try running:
dos2unix script.sh
What this does is change line endings from from Windows to unix format. i.e. it strips \r (CR) from line endings to change them from \r\n (CR+LF) to \n (LF).
Also, on a HTML note, you're missing a closing tag for "< HEAD >" after your title tags.
You can also do "od -c filename" or "grep pattern filename | od -c"
to see if there are any hidden characters in there.

Resources