54

I just found out about the bash extglob shell option here:- How can I use inverse or negative wildcards when pattern matching in a unix/linux shell?

All the answers that used shopt -s extglob also mentioned shopt -u extglob to turn it off. Why would I want to turn something so useful off? Indeed why isn't it on by default? Presumably it has the potential for giving some nasty surprises. What are they?

Community
  • 1
  • 1
hardcode57
  • 1,497
  • 2
  • 11
  • 10
  • 1
    One thing to consider is that getting used to this being enabled in your profile may result in some confusion if you run into a situation where your personalized profile configuration isn't applied (rebuilt machine, shell scripts which may run on other machines, etc). There's some benefit to sticking close to defaults. This is definitely a conservative viewpoint, however. Your mileage may vary. – bshacklett Aug 13 '19 at 15:35

2 Answers2

50

No nasty surprises -- default-off behavior is only there for compatibility with traditional, standards-compliant pattern syntax.


Which is to say: It's possible (albeit unlikely) that someone writing fo+(o).* actually intended the + and the parenthesis to be treated as literal parts of the pattern matched by their code. For bash to interpret this expression in a different manner than what the POSIX sh specification calls for would be to break compatibility, which is right now done by default in very few cases (echo -e with xpg_echo unset being the only one that comes immediately to mind).

This is different from the usual case where bash extensions are extending behavior undefined by the POSIX standard -- cases where a baseline POSIX shell would typically throw an error, but bash instead offers some new and different explicitly documented behavior -- because the need to treat these characters as matching themselves is defined by POSIX.

To quote the relevant part of the specification, with emphasis added:

An ordinary character is a pattern that shall match itself. It can be any character in the supported character set except for NUL, those special shell characters in Quoting that require quoting, and the following three special pattern characters. Matching shall be based on the bit pattern used for encoding the character, not on the graphic representation of the character. If any character (ordinary, shell special, or pattern special) is quoted, that pattern shall match the character itself. The shell special characters always require quoting.

When unquoted and outside a bracket expression, the following three characters shall have special meaning in the specification of patterns:

  • ? - A question-mark is a pattern that shall match any character.
  • * - An asterisk is a pattern that shall match multiple characters, as described in Patterns Matching Multiple Characters.
  • [ - The open bracket shall introduce a pattern bracket expression.

Thus, the standard explicitly requires any non-NUL character other than ?, * or [ or those listed elsewhere as requiring quoting to match themselves. Bash's behavior of having extglob off by default allows it to conform with this standard in its default configuration.


However, for your own scripts and your own interactive shell, unless you're making a habit of running code written for POSIX sh with unusual patterns included, enabling extglob is typically worth doing.

Community
  • 1
  • 1
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
2

Being a Kornshell person, I have extglob on in my .bashrc by default because that's the way it is in Kornshell, and I use it a lot.

For example:

$ find !(target) -name "*.xml"

In Kornshell, this is no problem. In BASH, I need to set extglob. I also set lithist and set -o vi. This allows me to use VI commands in using my shell history, and when I hit v, it shows my code as a bunch of lines.

Without lithist set:

for i in *;do;echo "I see $i";done

With listhist set:

for i in *
do
    echo "I see $i"
done

Now, only if BASH had the print statement, I'd be all set.

David W.
  • 105,218
  • 39
  • 216
  • 337
  • 2
    bash's preferred replacement for echo is a slightly extended version of `printf`, which ksh _does_ also have... – Charles Duffy Jun 19 '13 at 15:25
  • 2
    @CharlesDuffy Yes, I know about `printf`. My problem is habit. I had been writing Kornshell script since the 1980s. Habit says when I write a quick shell script on the command line, use `print` and not `echo`. BASH and KSH are about 98% compatible. It's just enough to drive me insane. I can switch between various languages w/o thinking because the syntax is different. BASH is enough like KSH that I forget I'm using BASH and not KSH. Then I try a Kornism like `r vi` or `cd foo bar`, and BASH gleefully rejects it. Grrrr... – David W. Jun 19 '13 at 16:51
  • 1
    @DavidW. - I converted several years ago, and before I got my script library ported over I had lots of bug-for-bug-compatible kshisms implemented as functions - `print`, `whence`, etc. But I've long since abandoned those crutches. The expressiveness of ! expansion has me wondering how I ever got by with `r`/`fc`. – Mark Reed Oct 21 '13 at 23:09
  • 1
    @MarkReed I depend heavily on what BASH calls *extglobs*, so that _BASH Bang_ is not only something I don't use, but is one of those frustrating non-compatibility issues I keep running into. It's so nice to say _Remove everything from this directory except for these two items_. Yes, I can set `shopt -s extglob`, and I set `lithist` which isn't quite compatible with ksh's way of editing multiple line commands that I frequently use. I'm just a dinosaur watching the mammals slowly taking over. Thinking about it makes me depressed and now I need some ice cream and reminisce about UUCP and usenet. – David W. Oct 22 '13 at 13:33
  • 1
    @DavidW. we can continue this over email. I'm at oldfart!mjreed.. ;) – Mark Reed Oct 22 '13 at 20:13