8

To focus on the @() syntax mentionned in this question :

[[ $OSTYPE == *@(darwin|freebsd|solaris|cygwin|openbsd)* ]]

Where does this syntax come from ? Why is it used in this case ? And what is the difference with :

[[ $OSTYPE =~ (darwin|freebsd|solaris|cygwin|openbsd) ]]

or

[[ $OSTYPE == *(darwin|freebsd|solaris|cygwin|openbsd) ]]

that all seems equivalents.

Is this syntax used in place of the =~ operator for better portability with regex ?

Thanks for your clarifications

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
SLePort
  • 15,211
  • 3
  • 34
  • 44
  • A possible duplicate: [How can I use inverse or negative wildcards when pattern matching in a unix/linux shell?](http://stackoverflow.com/a/217208/3776858) – Cyrus Mar 05 '16 at 10:10
  • @Cyrus My question was more 'Why using this syntax' than 'How to get a result'. – SLePort Mar 05 '16 at 10:21
  • Thanks @choroba. So nothing to do with `COMP_TYPE` nor list completions... The example above is extract from on a bash completion code, that's was caused confusion to me. – SLePort Mar 05 '16 at 10:25
  • @glenn jackman When i read the initial question, it seemed to me a bit more general about the global syntax, flow control and return values of the line and subsequent code. My intention was to focus on the `@()` syntax, interest and efficiency against other solutions. When i wrote the question, i missed in the inital question the comment about the `extglob` mode and the details about `@()`. Should i delete this question ? If so, sorry for the lost time. – SLePort Mar 05 '16 at 13:58

2 Answers2

8

Search for the extglob option in man bash:

If the extglob shell option is enabled using the shopt builtin, several extended pattern matching operators are recognized. In the following description, a pattern-list is a list of one or more patterns separated by a |. Composite patterns may be formed using one or more of the following sub-patterns:

?(pattern-list)
    Matches zero or one occurrence of the given patterns
*(pattern-list)
    Matches zero or more occurrences of the given patterns
+(pattern-list)
    Matches one or more occurrences of the given patterns
@(pattern-list)
    Matches one of the given patterns
!(pattern-list)
    Matches anything except one of the given patterns
choroba
  • 231,213
  • 25
  • 204
  • 289
3

This uses rules explained in the Pattern Matching section of man bash:

[[ $OSTYPE == *@(darwin|freebsd|solaris|cygwin|openbsd)* ]]

This uses regular expressions to perform the matching:

[[ $OSTYPE =~ (darwin|freebsd|solaris|cygwin|openbsd) ]]

These are very different mechanisms, with different performance implications. There are no patterns in the values darwin, freebsd, ..., these are simple literal strings. The @(...) syntax is perfect for such simpler matching logic, so using regular expressions seems overkill.

In this example both writing styles give the same behavior, it's just that they perform the matching through different mechanisms. If instead of a list of literal strings like darwin, freebsd, ... you had more complex regex patterns, then the first writing style wouldn't be an option, you would need to use the second version with full regex power.

Is this syntax used in place of the =~ operator for better portability with regex ?

It is used because it is good enough for the purpose, regex not needed.

janos
  • 120,954
  • 29
  • 226
  • 236
  • It's also used with regex a few lines later `local mansect="@([0-9lnp]|[0-9][px]|3?(gl|pm))". ` – SLePort Mar 05 '16 at 12:18
  • That's not a regex. It's a common mistake to confuse shell wildcard patterns with regex, because they look similar. This example you gave will be interpreted differently when parsed as a shell wildcard and as a regex. – janos Mar 05 '16 at 12:44
  • You're right. Two mistakes + one duplicate. It's not my day (-; – SLePort Mar 05 '16 at 14:15