1

I usually like to echo certain string which have an exclamation point in them. And while i know how to escape them to prevent expansion by the Shell, i noticed it also print the backslash...

echo "\!" # will print \! instead of just !

Contrary to other tool like sed which does not print the backslash if used to prevent expansion of possible valid parameter used by sed:

echo "test" | sed 's/^\(.*\)$/\1 \!/' # print -> test !
echo "test" | sed 's/^\(.*\)$/\1 !/' # also print -> test !
echo "test" | sed "s/^\(.*\)$/\1 ! /" # also print -> test !, though needed to put a space or use a backslash for it to show correctly

How can i do the same with echo or I'm i obliged to use other tools like sed?

EDIT:

Just noticed using '' instead of "" with the echo example above works for printing ! without shell expansion (both with and without the backslash), though:

  • It wouldn't work in instance when one want to use command substitution with echo, since it only work with ""...

1 Answers1

2

You need to escape it or quote it, not both:

echo \!
echo "!"

Bash history expansion ignores escaped exclamation marks, single-quoted exclamation marks, and exclamation marks which appear just before a closing double quote. See the History Interaction section of the manual for details. So

echo '!'

also works, and without having to think about where the exclamation mark is.

You can combine single quotes with variable expansion by using printf instead of echo. You can also combine multiple forms of quoting in the same command-line:

echo '!'"$(echo test)"

In general though, printf is better than echo. As others have mentioned you can also disable history expansion entirely; non-interactive shells don’t enable it by default.

Stephen Kitt
  • 434,908
  • Using echo "!" works yes, but it usually won't if used with command substitution, like so: echo "!$(echo "test")" (although it's probably because of the $ character). Any way around it? – Nordine Lotfi Mar 25 '21 at 15:14
  • OH, didn't thought of using printf like this! Guess that works with echo too: echo "$(echo "test")""!" yep, works! Thanks for the idea – Nordine Lotfi Mar 25 '21 at 15:17
  • 1
    FYI, i used the term usually loosely. eg: this doesn't work, unless you do X Y Z which i don't know/didn't thought about. – Nordine Lotfi Mar 25 '21 at 15:19
  • Or escape with single quotes. Which is the better way anyway, if you need something like foo!bar, or whatever where the ! isn't in one of the positions that don't trigger history expansion – ilkkachu Mar 25 '21 at 15:25
  • How safe it is to use ! inside double quotes and in which condition depends on the version of bash. – Stéphane Chazelas Mar 25 '21 at 15:26
  • also echo "!" doesn't really seem to work in Zsh. Or Ksh. – ilkkachu Mar 25 '21 at 15:28
  • @ilkkachu, which ksh would that be? I'm not aware of any ksh implementation that implemented csh history expansion (and zsh disables banghist when in ksh emulation) – Stéphane Chazelas Mar 25 '21 at 15:30
  • @StéphaneChazelas, whatever the one on Debian and Ubuntu is. – ilkkachu Mar 25 '21 at 15:37
  • @ilkkachu, there are several implementations of ksh available on Debian/Ubuntu. mksh and ksh93 or ksh2020 depending on the version. ksh2020 has been abandoned so Debian is going back to ksh93 IIRC. In any case echo "!" outputs ! in all the ones I've tried here. – Stéphane Chazelas Mar 25 '21 at 15:41
  • @StéphaneChazelas, this: https://packages.debian.org/stretch/ksh and this: https://packages.ubuntu.com/focal/ksh It's mentioned also here: https://github.com/att/ast/blob/master/src/cmd/ksh93/RELEASE#L1827 – ilkkachu Mar 25 '21 at 15:48
  • @ilkkachu, but yes, you're right, it seems ksh93 implemented csh-style history expansion in ksh93r, though I find it's not enabled by default here and it's not documented in the Debian man page (though it is in ksh --man). TIL – Stéphane Chazelas Mar 25 '21 at 15:48
  • @StéphaneChazelas, yes, you're right, I had to manually enable it. Didn't think too much of that, since I have it disabled and have to manually enable it anyway... – ilkkachu Mar 25 '21 at 15:51