3

The exclamation mark has a special function that I don't care to understand and its significance is a positive pain in my rear whenever I need to use echo (or any other command involving strings) in the dynamic creation of scripts. Putting ! in single quotes

# echo 'Testing!'
Testing!

works, but I have to use double quotes in bash for reasons of consistency. However, this has its problems:

# echo -e "Testing\!"
Testing\!

How can I properly escape ! in double quotes?

Melab
  • 2,594
  • 7
  • 30
  • 51
  • 1
    First of all, I 100% agree with you that the `!` in Bash is more painful than useful. If I wanted a C shell, I know where to find it — but I don't and I loathe the Bash `!` doing insane history-stuff. Why do you have to use double quotes for consistency when they don't work properly? Anyway, I suggest using [`set +H`](https://www.gnu.org/software/bash/manual/bash.html#The-Set-Builtin) to turn off the `!` history matching mechanism. Sanity will prevail — sea shells can be left on the sea shore where they belong and will, with luck, be washed away on the tides of history. – Jonathan Leffler Sep 23 '15 at 04:28
  • Incidentally, I think it's only a problem in interactive shells. In shell scripts, the `-H` option is turned off, and can't effectively be turned on. That is, writing `set -H` and `echo "Hi!"` in a shell script does not trigger the error. – Jonathan Leffler Sep 23 '15 at 04:35
  • 1
    @tripleee: The only problem with the duplicate is that it doesn't mention how to turn history off. Either the answer here needs to be merged with the answers to the other question, or this is a different question. That one asks "What is the `!` notation doing?" and this one asks "How do I stop the `!` notation doing what it does?". – Jonathan Leffler Sep 23 '15 at 04:40
  • @JonathanLeffler How is that? The accepted answer explains how to turn it off. (Maybe it should also mention the synonym `set +H`, though.) – tripleee Sep 23 '15 at 04:42
  • @tripleee: I looked for `+H` and didn't see it or even think to look for ornate alternatives that I won't remember. Would you be so kind as to add something like _'(or it's shorthand, `set +H`)'_ to your answer. – Jonathan Leffler Sep 23 '15 at 04:44
  • @JonathanLeffler Welp, it's there now. Thanks for the feedback. – tripleee Sep 23 '15 at 04:44
  • @tripleee: Thanks. Duplicity (of this question with that one) now accepted. – Jonathan Leffler Sep 23 '15 at 04:46

1 Answers1

2

To turn off history expansion, use:

set +H

Documentation

From man bash:

HISTORY EXPANSION
The shell supports a history expansion feature that is similar to the history expansion in csh. This section describes what syntax features are available. This feature is enabled by default for interactive shells, and can be disabled using the +H option to the set builtin command (see SHELL BUILTIN COMMANDS below). Non-interactive shells do not perform history expansion by default. [Emphasis added.]

Escaping ! when history expansion is on

If history expansion is enabled, ! will be an active character unless (1) it is escaped with a backslash, or (2) it is in single-quotes.

For example, to establish a history, let's enable history and run the ls command:

$ set -H
$ ls dummy
ls: cannot access dummy: No such file or directory

Now use !:

$ echo !ls
echo ls dummy
ls dummy

Thus, history expansion made a substitution. Let's try it double-quotes:

$ echo "!ls"
echo "ls dummy"
ls dummy

It is still active. If we need it to be disabled in double-quotes, it must be escaped with a backslash:

$ echo "\!ls"
\!ls

Or else we can put it in single-quotes:

$ echo '!ls'
!ls

However, I agree with Jonathan Leffler's comment: it is best to keep history expansion turned off. I have set +H in my ~/.bashrc.

How can I properly escape ! in double quotes?

To eliminate the extra backslash seen here:

$ echo -e "Testing\!"
Testing\!

Use single quotes:

$ echo -e "Testing"'!'
Testing!
John1024
  • 109,961
  • 14
  • 137
  • 171
  • But escaping it in double quotes prints the backslash, too! That is not normal "escaping". – Melab Sep 23 '15 at 23:31
  • @Melab Yes, that is ugly. I suspect that that behavior is required for compatibility among scripts. As discussed in the last section of the answer, the solution, if history expansion is on, is to use single-quotes for the `!`. – John1024 Sep 23 '15 at 23:45