1

Trying to understand why does the grep manual state the character classes with one square bracket.

https://www.gnu.org/software/grep/manual/html_node/Character-Classes-and-Bracket-Expressions.html

For example, it states: use [:lower:] to match lower case. Yet in the terminal, I use it and my result is:

$ grep [:lower:] test
grep: character class syntax is [[:space:]], not [:space:]

I've had no end of issues trying to use/understand this manual, what's wrong with it? It only seems to work with double [[]], but there isn't any explanation as to why the manual says just use [] instead.

1 Answer 1

3

Trying to understand why does the grep manual state the character classes with one square bracket.

Because character classes as such only have one set of brackets. You just need to put them inside bracket expressions too, which means in the end you have two sets.

The manual starts by giving the context of a bracket expression, one that has, well, the brackets around it:

A bracket expression is a list of characters enclosed by [ and ].

The following paragraphs assume that context.

Within a bracket expression, a range expression consists of two characters separated by a hyphen.

Finally, certain named classes of characters are predefined within bracket expressions, as follows.

The two characters and a hyphen also need to be within brackets, i.e. the whole thing is [a-f], not just a-f. (*)

Character classes also go within the bracket expression, so e.g. a character class [:upper:] is wrapped in brackets to give the bracket expression [[:upper:]]. Or, in case you put more than just one character class within the brackets, you could have [-[:upper:][:digit:]] which would match the dash, uppercase letters or digits. (one plain character and two character classes within a single bracket expression.)

As for why the syntax is like that, I don't know.

Note that the manual even has the full example on how to use character classes:

... for example, [[:alnum:]] means the character class of numbers and letters in the current locale.

And it says:

Note that the brackets in these class names are part of the symbolic names, and must be included in addition to the brackets delimiting the bracket expression.

The error message you get is also described:

If you mistakenly omit the outer brackets, and search for say, [:upper:], GNU grep prints a diagnostic and exits with status 2, on the assumption that you did not intend to search for the regular expression [:epru].

So, it really doesn't look like it tells to use just one set of brackets for the whole deal.

Except that... The example for [:alnum:] goes (and [:alpha:] is similar):

[:alnum:] Alphanumeric characters: [:alpha:] and [:digit:]; in the ‘C’ locale and ASCII character encoding, this is the same as [0-9A-Za-z].

This is false. [0-9A-Za-z] is the same as [[:alnum:]], not [:alnum:]. [:alnum:] would be 0-9A-Za-z, but either would need the outer brackets to do anything useful.

Of course, the error message also doesn't appear to mention the distinction between a character class and the enclosing bracket expression, so yes, they're being a bit unclear there.


Note that as the brackets are also glob characters in the shell, you should quote the pattern, e.g.

grep '[[:lower:]]' test

Otherwise, the pattern would be expanded by the shell to :, e, l, o, r, or w, if any files with those exact names exist.

(* Note that caveats apply with characters ranges, their interpretation depends on the locale, and in Bash the globasciiranges option, which I think has been shown to act weirdly.)

7
  • See lists.gnu.org/archive/html/bug-bash/2021-02/msg00054.html if you need a reference to globasciiranges behaving weirdly. Nov 28, 2022 at 20:25
  • @StéphaneChazelas, yes, I think that's exactly what I was thinking. I didn't remember where it was, though, thanks.
    – ilkkachu
    Nov 28, 2022 at 20:30
  • 1
    @johnsmith, hmm. So what's the question exactly? You wrote "I've had no end of issues trying to use/understand this manual, what's wrong with it?" -- so if you're looking for what's wrong with the manual, I guess it could be that it's just written in a style that doesn't work well with you. The way I read it doesn't tell to use just [:lower:], but to use [:lower:] within [ ], ending up with [[:lower:]].
    – ilkkachu
    Nov 28, 2022 at 20:39
  • 1
    @johnsmith, oh, indeed, there's e.g this: "Alphanumeric characters: [:alpha:] and [:digit:]; in the ‘C’ locale and ASCII character encoding, this is the same as [0-9A-Za-z]." -- and you're quite right, that's wrong. [0-9A-Za-z] is the same as [[:alnum:]], not [:alnum:]. Now, I can understand them listing the classes with only one set of brackets, as you can indeed put more than one class inside one set of brackets (e.g. [[:alpha:][:digit:]] is fine). But those examples are wrong. Sorry, I didn't even see that the first time...
    – ilkkachu
    Nov 28, 2022 at 21:01
  • 1
    Ah, that actually also makes sense. That's why they didn't put [[:digit:]] or whatever. I didn't know you could nest them into one big one like you did with alpha and digit. Ok that, explains me a lot!! Thank you!
    – john smith
    Nov 28, 2022 at 21:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .