EDIT: the command substitution is not necessary for the surprising behavior, although it is the most common use case. The same question applies to just echo "'!b'"
b=a
# Enable history substitution.
# This option is on by default on interactive shells.
set -H
echo '!b'
# Output: '!b'
# OK. Escaped by single quotes.
echo $(echo '!b')
# Output: '!b'
# OK. Escaped by single quotes.
echo "$(echo '$b')"
# Output: '$b'
# OK. Escaped by single quotes.
echo "$(echo '!b')"
# Output: history expands
# BAD!! WHY??
- In the last example, what is the best way to escape the
!
? - Why was it not escaped even if I used single quotes, while
echo "$(echo '$b')"
was? What is the difference between!
and$
? - Why was does
echo $(echo '!b')
(no quotes) work? (pointed by @MBlanc).
I would prefer to do this without:
set +H
as I would needset -H
afterwards to maintain shell statebackslash escapes, because I need one for every
!
and it has to be outside the quotes:echo "$(echo '\!a')" # '\!a'. # No good. echo "$(echo 'a '\!' b '\!' c')" # a ! b ! c # Good, but verbose.
echo $(echo '!b')
(no quotes), because the command could return spaces.
Version:
bash --version | head -n1
# GNU bash, version 4.2.25(1)-release (i686-pc-linux-gnu)
echo "$(echo \!b)"
works for me under Bash-3.2 – Heavenly!
in the string, but it works. Please add your comment to an answer. There is still the why question. – Sukhumset +H
myself if I were writing a script. I hope a bash expert sees this and enlightens us. Good luck! :) – Heavenlyecho "!b"
... what did you expect? – Noiselessecho "$(echo -e '! \bb')"
orecho "$(echo -e "! \bb")"
work? Don't both of these lead toecho "!b"
? – Hype!
prevents!
expansion. Thats clear in the man pages. – Sukhumecho "$(echo '$b')"
gives$b
and nota
? (it expands "only once", while the!
command expands twice) – Sukhum-e
? With-e
,\b
is backspace, and that makes by brain twist even more. Without the-e
the result is different. – Sukhum-e
enables interpretation of backslash escapes; that would explain different results with and without it. – Hypeset -H
in yourbashrc
. It's a feature that hails from a day when the readline library didn't exist yet and command-line editing was far more cumbersome. – Deliciadeliciousset +H
to turn history expansion off -set -H
turns it on. – Resolvable