Bash’s declare -p HISTIGNORE brings bash to a halt! Why

bashcommand historyglob

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.

Best Answer

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.

Related Question