6

I took a closer look on this phenomenon after I stumbled over it in two other questions today. I've tried all of this with the default set -H (history expansion on).

To test a script, I often do things like echoing a multi-line string and pipe it through a script, but in some cases it gives an error:

$ echo "foo
bar" | sed '/foo/!d'
bash: !d': event not found
> 

The ! seems to trigger history expansion, although it is enclosed with single quotes. The problem seems to be the occurrence of the double quote in the same line, because

$echo $'foo\nbar' | sed '/foo/!d'

works as well as

$echo "foo
bar" |
> sed '/foo/!d'

My suspicion: History expansion is applied linewise, so the ' after a single " is considered to be escaped, so the following ! is not escaped.

Now my question: Is this a bug or expected behavior? Reproduced with bash versions 4.2.30 and 4.4.12.

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
Philippos
  • 13,237
  • 2
  • 37
  • 76
  • 1
    Just tried with `zsh` (history expansion on): No such problem. Really seems to be a bug in `bash` – Philippos Sep 08 '17 at 07:54
  • 1
    The problem is poor implementation of history expansion in `bash`. You can disable the whole implementation by adding `set +H` to `.bashrc`. In that case, `bash` never attempts to do any history expansion stuff anywhere (that is, behave like proper bourne shell) and you'll have less nasty surprises. – Mikko Rantalainen Nov 14 '18 at 07:41

1 Answers1

6

I reported this to [email protected] and got this answer:

History expansion is explicitly line-oriented, and always has been. There's not a clean way to make it aware of the shell's current quoting state (mostly since it's a library independent of the shell). Maybe there's a way to use one of the existing callback functions to do it.

This sounds to me like "this is not a bug, because we can't do it any better with the current implementation".

Update

I lost interest in this subject after switching to zsh. Now I tried with bash version 5.1.4 and found the problem can't be reproduced anymore. So somewhere between 4.4.12 and 5.1.4, somebody did fix this.

Philippos
  • 13,237
  • 2
  • 37
  • 76