Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the difference between <<EOF and <<\EOF heredocs in shell

Tags:

bash

shell

sh

I have noticed several distinction between them:

Inside a <<EOF heredoc, new values can not be assigned to variables:

bash <<EOF
s=fds
echo $s
EOF

will print empty line, where

bash <<\EOF
s=fds
echo $s
EOF

will print the value of the variable s.

Global variables can be accessed within <<EOF but not within <<\EOF (with export it is possible to access variables inside <<\EOF):

s=fds
bash <<EOF
echo $s
EOF

will print the value fds, where,

s=fds
bash <<\EOF
echo $s
EOF

will print empty line.

So what are the differences between them and what is the legitimate documented behavior?

like image 244
Jahid Avatar asked Jul 28 '15 14:07

Jahid


People also ask

What does << EOF mean in shell script?

This operator stands for the end of the file. This means that wherever a compiler or an interpreter encounters this operator, it will receive an indication that the file it was reading has ended. Similarly, in bash, the EOF operator is used to specify the end of the file.

What is EOF and EOT?

On a serial connection an EOT (End Of Transmission) character indicates a desire to end the transmission. Serial connections are usually accessed using a file driver. When the serial transmission ends, the file driver reports this as an EOF (End Of File) condition. EOF is not a character.

What does EOF mean Linux?

In computing, end-of-file (EOF) is a condition in a computer operating system where no more data can be read from a data source. The data source is usually called a file or stream.


2 Answers

From the POSIX spec:

If any character in word is quoted, the delimiter shall be formed by performing quote removal on word, and the here-document lines shall not be expanded. Otherwise, the delimiter shall be the word itself.

So the <<EOF version has the shell expand all variables before running the here doc contents and the <<\EOF (or <<'EOF' or <<EO'F' etc.) versions don't expand the contents (which lets bash in this case do that work).

Try it with cat instead of bash for a clearer view on what is happening.

Also with printf '[%s]\n' "$s" and/or possibly bash -x instead of bash:

$ bash -x <<EOF
s=fds
printf '[%s]\n' "$s"
EOF
+ s=fds
+ printf '[%s]\n' ''
[]

$ bash -x <<\EOF
s=fds
printf '[%s]\n' "$s"
EOF
+ s=fds
+ printf '[%s]\n' fds
[fds]
like image 76
Etan Reisner Avatar answered Sep 20 '22 12:09

Etan Reisner


Documentation: http://www.gnu.org/software/bash/manual/bash.html#Here-Documents

In your first example the delimiter is unquoted, so variable expansion occurs and it's like you're running the code

echo "s=fds
echo $s" | bash

which expands $s in the current shell, where it's empty. So the new shell sees

s=fds
echo 
like image 34
melpomene Avatar answered Sep 21 '22 12:09

melpomene