bash multi line command with comments after the continuation character

Consider

echo  # this is a comment
foo

This gives:

$ sh foo.sh
 # this is a comment
foo.sh: line 2: foo: command not found

After some searching on the web, I found a solution by DigitalRoss on sister site Stack Overflow. So one can do

echo `: this is a comment` 
foo

or alternatively

echo $(: this is a comment) 
foo

However, DigitalRoss didn’t explain why these solutions work. I’d appreciate an explanation. He replied with a comment:

There used to be a shell goto command which branched to labels
specified like : here. The goto is gone but you can still use the
: whatever syntax … : is a sort of parsed comment now.

But I’d like more details and context, including a discussion of portability.

Of course, if anyone has other solutions, that would be good too.

See also the earlier question How to comment multi-line commands in shell scripts?.


Take home message from the discussion below.
The `: this is a comment` is just a command substitution.
The output of : this is a comment is nothing, and that
gets put in the place of `: this is a comment`.

A better choice is the following:

echo `# this is a comment` 
foo

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Comments end at the first newline (see shell token recognition rule 10), without allowing continuation lines, so this code has foo in a separate command line:

echo # this is a comment 
foo

As for your first proposal, the backslash isn’t followed by a newline, you’re just quoting the space: it’s equivalent to

echo ' # this is a comment'
foo

$(: this is a comment) substitutes the output of the command : this is a comment. If the output of that command is empty, this is effectively a highly confusing way to insert a comment in the middle of a line.

There’s no magic going on: : is an ordinary command, the colon utility, which does nothing. The colon utility is mostly useful when the shell syntax requires a command but you happen to have nothing to do.

# Sample code to compress files that don't look compressed
case "$1" in
  *.gz|*.tgz|*.bz2|*.zip|*.jar|*.od?) :;; # the file is already compressed
  *) bzip2 -9 "$1";;
esac

Another use case is an idiom for setting a variable if it’s not already set.

: "${foo:=default value}"

The remark about goto is a historical one. The colon utility dates back from even before the Bourne shell, all the way to the Thompson shell, which had a goto instruction. The colon then meant a label; a colon is a fairly common syntax for goto labels (it’s still present in sed).

Method 2

You can achieve this using Bash arrays, e.g.

#!/bin/bash
CMD=(
  echo  # this is a comment
  foo
  )

"${CMD[@]}"

This defines an array, $CMD, and then expands it. Once expanded the resulting line is evaluated, so in this case echo foo is executed.

The text between ( and ) defines the array and is subject to the usual bash syntax, so everything on a line after # is ignored.

Note about preserving quoted whitespace

${CMD[@]} expands to a single string which is the concatenation of all the elements, separated by a space. Once expanded, Bash would then parse the string into tokens in the usual manner (c.f $IFS), which is often not what we want.

By contrast if the expansion is wrapped in double quotes, i.e. "${CMD[@]}", then each element in the array is preserved. Consider the difference between hello world second item and "hello world" "second item".

Illustrative example:

# LIST=("hello world" "second item")

# for ITEM in ${LIST[@]}; do echo $ITEM; done
hello
world
second
item

# for ITEM in "${LIST[@]}"; do echo $ITEM; done
hello world
second item

Method 3

Don’t do $(: comment). That’s not a comment – that’s a subshell – another whole new shell process for most shells. Your goal is to do less w/ your input, not more, which is what that would do – even if it is pointless.

You can instead do…

printf '<%s>n' some args here ${-##*"${--

                my long comment block

                }"}  and "more ${-##*"${--

                and another one in the
                middle of the quoted string
                there shouldn't be any special &
                (character) `echo issues here i hope >&2`
                basically anything that isn't a close }
                $(echo the shell is looking for one >&2)
                }$(echo "}'"" need backslash escaping >&2
                                )${-##*${--

                nesting is cool though

             }}"}here too"

}'" need backslash escaping
<some>
<args>
<here>
<and>
<more here too>

Basically what’s happening there is the shell is doing a substitution. It substitutes the value of the special shell parameter $- twice each time. It’s a short string anyway, but it is always set – and so the inner substitution – which is interpreted as a pattern to strip from the outer – doesn’t expand to the contents between the parentheses when I use the - expansion form.

Here:

bash -x <<""
printf %s\n '${-##*"'${-- a set param doesn't expand to this optional text }'"}'

+ printf '%sn' '${-##*"hxB"}'
${-##*"hxB"}

See? So it’s just expanded twice. As soon the shell finds the parameter is set everything in the optional expansion field is discarded, pretty much, and it expands to its whole value which is removed from itself and so to nothing at all. In most shells you need not even escape quotes, but bash requires it.

Better still is:

COMMENT=
echo      ${COMMENT-"
           this will work the same way
           but the stripping isn't
           necessary because, while
           the variable is set, it is also
           empty, and so it will expand to
           its value - which is nothing
           "} this you'll see

this you'll see


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x