102

Recently, I stumbled upon a multiline comment type I have never seen before - here is a script example:

echo a
#
: aaa 
: ddd 
#
echo b

This seems to work, even vim syntax-highlights it. What is this style of commenting called and how to I find more info about it?

2
  • 1
    What if you instead wrap your code into function to comment it out? CommentedOutBlock() { echo "test"; }
    – Buksy
    Commented Nov 8, 2016 at 12:54
  • As others have mentioned already, multi-line comments are not available natively. So I use if false; then <how many ever lines you want> fi
    – psykid
    Commented Apr 29, 2020 at 11:48

4 Answers 4

145

That is not a multi-line comment. # is a single line comment. : (colon) is not a comment at all, but rather a shell built-in command that is basically a NOP, a null operation that does nothing except return true, like true (and thus setting $? to 0 as a side effect). However since it is a command, it can accept arguments, and since it ignores its arguments, in most cases it superficially acts like a comment. The main problem with this kludge is the arguments are still expanded, leading to a host of unintended consequences. The arguments are still affected by syntax errors, redirections are still performed so : > file will truncate file, and : $(dangerous command) substitutions will still run.

The least surprising completely safe way to insert comments in shell scripts is with #. Stick to that even for multi-line comments. Never attempt to (ab)use : for comments. There is no dedicated multi-line comment mechanism in shell that is analogous to the slash-star /* */ form in C-like languages.


For the sake of completeness, but not because it is recommended practice, I will mention that it is possible to use here-documents to do multi-line "comments":

: <<'end_long_comment'
This is an abuse of the null command ':' and the here-document syntax
to achieve a "multi-line comment".  According to the POSIX spec linked 
above, if any character in the delimiter word ("end_long_comment" in 
this case) above is quoted, the here-document will not be expanded in 
any way.  This is **critical**, as failing to quote the "end_long_comment" 
will result in the problems with unintended expansions described above. 
All of this text in this here-doc goes to the standard input of :, which 
does nothing with it, hence the effect is like a comment.  There is very 
little point to doing this besides throwing people off.  Just use '#'.
end_long_comment
5
  • 30
    +1 very important to keep the single quotes on the << line -- that turns off substitution and expansion. Commented Apr 27, 2012 at 12:11
  • 4
    And as an extra note, filling up shell scripts with : for things that should be comments will cause extra RAM/CPU consumption. It won't mater for simple things on your desktop, but if it's something executed hundreds or thousands of times a second you'll be doing nothing, mighty fast.
    – bahamat
    Commented Aug 29, 2012 at 21:28
  • 3
    @bahamat: if you execute something hundreds or thousands of times a second, I hope you won't write it in shell... =/
    – 7heo.tk
    Commented May 24, 2014 at 1:40
  • 1
    Sometimes, using the null utility for multiple lines of text may be useful. Starting the comment with : <<=cut makes it possible to write POD in shell scripts, see this example for details. This makes it possible to use perldoc script.sh. However, the multi-line comment shown in this answer is something that should definitely be a comment block (each line starting with # ).
    – basic6
    Commented Dec 4, 2014 at 10:14
  • Here's a nice discussion on heredocs, used for both comments and other interesting use cases (even including dynaimc script generation): tldp.org/LDP/abs/html/here-docs.html#EX71C
    – bguiz
    Commented Aug 22, 2016 at 1:02
29

It's not any style of commenting. the : built-in command does absolutely nothing; it's being abused for commenting here.

$ help :
:: :
    Null command.

    No effect; the command does nothing.

    Exit Status:
    Always succeeds.
26

In early shells, the colon was the only way to create comments.

However, it is not a true comment, because the line is parsed in exactly the same way as any other command is parsed, and that may have side effects. For example:

: ${a:=x} # assigns the value 'x' to the variable, 'a'

: $(command) # executes 'command'

(Sometimes the colon is use solely for the purpose of invoking those side effects, but then it’s not being used as a comment.)

It is sometimes convenient to use the colon to comment out a section of a script:

: '
while [ "$n" -ne "$x" ]
do
  : whatever
done
'

This is a great timesaver over preceding each line with #, particularly if the commenting out is only temporary.

4
  • 3
    That single-quote commenting method doesn't work on any section of script that itself uses single-quotes. And if you are using quotes anywhere near as much as you should, that means you'll have legitimate single quotes sprinkled all throughout the script. It is so much simpler to just use any decent editor that lets you do block linewise comments.
    – jw013
    Commented Jan 16, 2013 at 21:18
  • You are quite right that it will only work if there are no single quotes in the quoted section. However, a script need not have a lot of single quotes. In looking over a few of my scripts, I find them relatively sparse, and many could be replaced by double quotes. Commented Jul 8, 2013 at 1:36
  • The choice of single quote or double quote should hardly be influenced by something as trivial and irrelevant a concern as whether the text of your script is itself a valid single-quoted string. Single quotes are used to prevent expansions, while double quotes allow certain expansions and require extra parsing. This is the real criteria for determining which to use.
    – jw013
    Commented Jul 11, 2013 at 3:27
  • This is by far the chicest way of doing it. Great for little blocks of documentation. I like it better than /* */ and ugh, don't get me started on <!-- -->!
    – alex gray
    Commented Sep 5, 2013 at 23:13
2

If your comment is at the end of the script, you can do it like this:

#!/bin/sh
echo 'hello world'
exec true
we can put whatever we want here
\'\"\$\`!#%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
abcdefghijklmnopqrstuvwxyz{|}~

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .