简体   繁体   中英

Why does line comment tricks for bash not work with exclamation mark "!"

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

(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.

  1. echo # !xxx

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

  1. echo `true # !xxx`

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

  1. 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` .

  1. 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.

  1. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM