3

In Bash, to do a negative file globbing I have the following 2 choices. Is there a difference between them ? Both return the same result :

$ ls f1.txt f2.txt f3.txt f4.txt $ ls f[!24]* f1.txt f3.txt $ ls f[^24]* f1.txt f3.txt 

1 Answer 1

4

The [!...] pattern matches a single character that is not part of the ... set within the square brackets. This is a filename globbing pattern used by POSIX shells.

The [^...] pattern works the same, but is a POSIX regular expression. This pattern is not generally portable to other shells as a filename globbing pattern, but the bash shell recognizes it and treats it as identical to the [!...] pattern.

If you have a choice to choose between these two when writing a filename globbing pattern, you should most probably use the portable POSIX variant [!...].

The POSIX standard says about the filename globbing pattern [...] in general:

If an open bracket introduces a bracket expression as in XBD RE Bracket Expression, except that the <exclamation-mark> character (!) shall replace the <circumflex> character (^) in its role in a non-matching list in the regular expression notation, it shall introduce a pattern bracket expression. A bracket expression starting with an unquoted <circumflex> character produces unspecified results. Otherwise, [ shall match the character itself.

The "XBD RE Bracket Expression" thing is the specification for [...] in regular expressions.

The standard leaves the use of [^...] in a filename globbing pattern "unspecified" and the bash shell (and a few others) have chosen to implement this as identical to [!...].

2
  • 2
    Note that the reason it's [!x] instead of [^x] is that ^ was a pipe operator in the Thompson/Bourne shell. It's ^ in regexps and about every other shell (except some direct Bourne descendants like ksh88). In csh, and interactive bash, zsh, ! is a history expansion operator so [^x] is preferred there even though [!x] is supported in zsh/bash (though conflicts with history expansion). In rc / es, ^ is some form of concatenation operator, it's [~x] there for negation. fish doesn't support bracket expressions. Commented Jan 24, 2022 at 6:59
  • 2
    (to clarify, ^ (which looked more like a ↑ at the time) was a pipe operator in the Thompson shell, but globbing was done with the /etc/glob helper (which gave their name to globs), and didn't support negation inside [...]. [!...] was likely introduced by the Bourne shell (which used | as pipe operator but kept ^ as well for backward compatibility). Commented Jan 24, 2022 at 7:48

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.