3

Executing the following code in GNU bash, Version 4.2.45(1)-release (x86_64-redhat-linux-gnu), Fedora 19 ...

shopt -s extglob
export HISTIGNORE="!(+(!([[\:space\:]]))+([[\:space\:]])+(!([[\:space\:]])))"
declare -p HISTIGNORE

... brings bash to a full stop. It does not print a command prompt hereafter. Why is that.

Background:

All I want to tell bash is to ignore any simple, i.e. one word command. Bash should not remember command lines like cd, pwd, history, etc. My original definition of the HISTIGNORE variable looked like this:

export HISTIGNORE="!(+(!([[:space:]]))+([[:space:]])+(!([[:space:]])))"

I added a \ backslash character before each : colon character because according to the bash info pages the latter separates each (extended) shell glob, i.e. pattern from another. Without escaping the single pattern does not have any effect and a simple command still makes it into history.

  • On my Bash 4.2.37, your commands work for me (simple commands don't appear in history) although bash takes a long time, minutes, to process declare -p HISTIGNORE – John1024 Jan 11 '14 at 22:59
  • I've already filed a bug report to bug-bash@gnu.org because even when bash should eventually return with a command prompt the delay it causes is unacceptable for me. – Tim Friske Jan 11 '14 at 23:01
4

Your pattern is very complex. Negating a regular expression tends to have exponential behavior in the size of the regular expression, and you have a negation inside a negation, which could lead to a double exponential. Ulp.

Nonetheless, such a long freeze is not desirable. I observe the same behavior on Debian with bash 4.2.37 on Debian, so report it as a bug upstream. But be prepared to be told that it would be too much work for too little benefit to make this edge case work.

In the meantime, I doubt that the pattern really does what you want. There's a much simpler way of ignoring single-word commands:

HISTIGNORE='+([a-z])'

Tweak this if you'd like to ignore even rare commands containing other characters in their name, or if you'd like to ignore whitespace. For example:

HISTIGNORE=$'*([\t ])+([-%+,./0-9\:@A-Z_a-z])*([\t ])'

Note that you don't need to, and indeed should not, export HISTIGNORE. This is a bash internal variable, not an environment variable.

  • Is it really necessary to escape a : colon character that is part for example of a POSIX character class? I also thought about cutting my rather complex HISTIGNORE value down to $'!(*[[\:space\:]]*)'. – Tim Friske Jan 11 '14 at 23:47
  • @TimFriske I don't know whether : needs to be escaped, I'm not a bash expert. You can avoid the negation by using the equivalent pattern +([![:space:]]), though a single level of nesting of negation should be ok. – Gilles Jan 11 '14 at 23:52
  • Don't you mean the ^ caret instead of ! exclamation character for negating the characters inside a class? – Tim Friske Jan 12 '14 at 0:16
  • @TimFriske In shell glob patterns, the standard is !, though many shells including bash also support ^. – Gilles Jan 12 '14 at 0:17
1

In the meantime I received the following answer from Chet Ramey from bug-bash@gnu.org:

  1. The matcher blows up and goes exponential when the backslashes are in there. I didn't investigate why.

  2. You don't need the backslashes; the colons are part of the patterns. The ignore pattern parser understands pattern syntax, so the colons in the bracket expressions don't split the value.

  3. The HISTIGNORE value without the backslashes seems to work using bash-4.2.45: single-word simple commands are not added to the history list.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.