Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I wanted to see how some ASCII art looked in terminal so:

$ cat <<EOF                                                                                                                                                                                  
> #          ____         _
> #  _   _  / __/  ___ _ | |_
> # | | | |/ /    /  _` || __|
> # | |_| |\ \__ 🐱 (_| || |_
> # |  _,_| \___\ \___,_| \__|
> # |_/
> #
bash: bad substitution: no closing "`" in ` || __|
# | |_| |\ \__ 🐱 (_| || |_
# |  _,_| \___\ \___,_| \__|
# |_/

The # octothorpes were there perchance, but now I'm confused.

$ cat <<EOF
> # echo hi
# echo hi

As expected.


$ cat <<EOF
> # `echo hello`
# hello

So bash gets at expanding `` and $( ) before cat does, but it doesn't care about # comments? What's the explanation behind this behaviour?

share|improve this question
Change cat <<EOF to cat <<\EOF. – jimmij Jan 29 at 0:34
If the commented line was output, then clearly it's not a comment. – muru Jan 29 at 0:37
@muru I don't mean a comment in that cat will ignore it, I meant a comment to be ignored by bash. – cat Jan 29 at 0:37
Since cat doesn't have any concept of comments at all, we're both talking of bash. A comment shouldn't affect the outcome at all. If it does, it's not a comment. – muru Jan 29 at 0:39
Is that micro cat? Is there a macro cat? You oughtta go big before you go small – mikeserv Jan 29 at 0:55
up vote 16 down vote accepted

This is more general than bash. In POSIX shell, your EOF is referred to as a word, in the discussion of here-documents:

If no characters in word are quoted, all lines of the here-document shall be expanded for parameter expansion, command substitution, and arithmetic expansion. In this case, the <backslash> in the input behaves as the <backslash> inside double-quotes (see Double-Quotes). However, the double-quote character ( '"' ) shall not be treated specially within a here-document, except when the double-quote appears within "$()", "``", or "${}".

Quoting is done using single-, double-quotes or the backslash character. POSIX mentions the here-documents in the discussion of quoting:

The various quoting mechanisms are the escape character, single-quotes, and double-quotes. The here-document represents another form of quoting; see Here-Document.

The key to understanding the lack of treatment of # characters is the definition for here-documents:

allow redirection of lines contained in a shell input file

That is, no meaning (other than possible parameter expansion, etc) is given to the data by the shell, because the data is redirected to another program: cat, which is not a shell interpreter. If you redirected to a shell program, the result would be whatever the shell could do with the data.

share|improve this answer
Perhaps better reason why # does not introduce comment in here-document is that it does not introduce comment in quoted string either and here-documents behave as quoted strings. – Jan Hudec Jan 29 at 7:56
For that, you have to do more reading between the lines, because POSIX does not mention comments and quoting in the same sentence (I think). Redirecting was the closest I found. – Thomas Dickey Jan 29 at 9:36
A # does not introduce a comment in a here document for the same reason it does not introduce a comment in "# $(echo foo)": a string is data, not code. – chepner Jan 29 at 16:36

Within a here document there are no comment lines.

man bash:

No parameter and variable 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, command substitution, and arithmetic expansion, the character sequence \ is ignored, and \ must be used to quote the characters \, $, and `.

So you need:

cat <<"EOF"
share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.