5

ref Inline comments for Bash?

We can use this tricks

echo abc `#put your comment here` \
     def `#another chance for a comment` \
     xyz etc

but these do not work if we have an exclamation mark in comment

echo 1 `# 2 !3`
<error>
-bash: !3: event not found

if we type it directly it will not be translated to an event

# 2 !3
<that is OK>

It seams that we need an other # symbol to workaround it.

echo 1 `# 2 #!3`
<that is OK>
1

or do we have to double the leading # symbol?

echo 1 `# # 2 !3`
<that is OK>
1
Pierre François
  • 5,850
  • 1
  • 17
  • 38
William Leung
  • 1,556
  • 17
  • 26
  • It's not specific to comments, you'd have the same issue in other pieces of code. You will want either to single-quote your comment, or to disable history expansion using `set +H` – Aaron Feb 11 '20 at 09:53
  • Does this answer your question? [How to escape history expansion exclamation mark ! inside a double quoted string?](https://stackoverflow.com/questions/22125658/how-to-escape-history-expansion-exclamation-mark-inside-a-double-quoted-string) – Aaron Feb 11 '20 at 09:54
  • @Aaron it seems to be a different issue – William Leung Feb 11 '20 at 09:56
  • Yeah somewhat, because the OP of the question used a syntax that would now work but didn't in bash < 4.4. The question and various answers do discuss the history expansion that is the root of your problem though. Doesn't quoting your exclamation marks work? – Aaron Feb 11 '20 at 09:58
  • @Aaron quote not works, but I found double the leading hash can workarounds – William Leung Feb 11 '20 at 09:59
  • It must be because expansion is performed twice as you're using a subshell. I'm afraid your double hash only works because you now have enough history that `!3` does refer to an history event and is expanded to its value (which is ignored since it's in a comment) rather than raise an error. You should try it just after having performed `history -c`. using `set +H` would be sure to work though – Aaron Feb 11 '20 at 10:01
  • @Aaron I am sure it is not related with history length, change !3 to !3333333 still works: `echo 1 \`# # 2 !333333\`` – William Leung Feb 11 '20 at 10:03
  • Hmm I don't get why it works, but if it works good enough I guess? I'll see if I can understand what's happening – Aaron Feb 11 '20 at 10:06
  • I've reproduced your double-hash trick and still don't understand why it works, but I've also been able to successfully use single-quotes to avoid the problem in a way I understand : both ``echo 1 `# 2 '!'3`` and ``echo 1 `# '2 !3'`` work without error in my shell (the leading hash must be left out of the comment to have a valid command though) – Aaron Feb 11 '20 at 10:24

1 Answers1

4

(The following explanation turned out to be WRONG though it explained everything. See the UPDATE as follows.)

  1. # !xxx

    This works as expected because ! is in the comment.

  2. echo # !xxx

    This also works as expected because ! is also in the comment.

  3. echo `true # !xxx`

    This also works because ! is still in the comment, though it's in the `...` context.

  4. echo `# !xxx`

    Why doesn't this work?

    I guess there's a little bug when Bash interprets the `...` part. In `...`, Bash always assumes (wrongly) the first WORD is a COMMAND name so it does not think ! is in a comment and so history expansion is triggered. That's to say, echo `# !xxx` is just like echo `COMMAND !xxx`.

  5. echo `# # !xxx`

    Why does this work?

    As explained in #4, the first # is parsed as a COMMAND so it's just like echo `COMMAND # !xxx` so now ! is in the comment.

  6. echo `## !xxx`

    This double hash does not work either.

    As explained in #4 and #5, here ## is the first WORD and it's parsed as the COMMAND name so it's also like echo `COMMAND !xxx`.

Note that, in the `...` context, the bug is only in the first round syntax parser. That's to say, even though Bash initially parses the # as a COMMAND name, it does not really run it as a command which is named #.


UPDATE 2020-03-04

The above explanation turned out to be WRONG though it explained everything. Please see the discussion in bug-bash mailing list.

I'd quote Chet's explanation here for easy reference:

> $ set -H
> $ true `# !xxx`
> bash: !xxx`: event not found

Well, the history comment character (#) is not found at the start of a word (here # is part of the word `#), so the rest of the line is processed for history expansion.

$ true `# # !xxx`

The history comment character is found at the start of a word (here the 2nd # itself is a word) and history expansion skips the rest of the line.

Readline history expansion knows very little about shell syntax; in particular, it doesn't know backquotes. It never has.

pynexj
  • 19,215
  • 5
  • 38
  • 56