5

I thought I understood the use of the optional ?(pattern-list) in bash (when extglob shell option is on) and by default in ksh. For example in bash:

$ shopt -s extglob
$ V=35xAB
$ echo "${V#?(35|88)x}" "${V#35}"
AB xAB

But when the matching prefix pattern is just one ?() or one *(), which introduce what I call optional patterns, the 35 is not omitted unless ## is used:

$ echo "${V#?(35|88)}" "${V#*(35|88)}"    # Why 35 is not left out?
35xA 35xA
$ echo "${V##?(35|88)}" "${V##*(35|88)}"  # Why is it omitted when ## is used?
xA xA

The same behaviour is reported when ?() and *() are used in a matching suffix pattern (using % and %%):

$ echo "${V%5?(xA|Bz)}"                   # 5xA is omitted
3
$ echo "${V%?(xA|Bz)}" "${V%*(xA|Bz)}"    # why xA is not left out?
35xA 35xA
$ echo "${V%%?(xA|Bz)}" "${V%%*(xA|Bz)}"  # xA is omitted when %% is used
35 35

I tested this issue in the bash releases 3.2.25, 4.1.2 and 4.1.6 and it makes me think that, perhaps, I had not properly understood the actual underlying shell mechanism for matching patterns.

May anybody shed light on this?

Thanks in advance

123
  • 10,778
  • 2
  • 22
  • 45
Jdamian
  • 3,015
  • 2
  • 17
  • 22
  • 1
    `#` matches the shortest possible occurrence of the pattern. `?()` matches zero or one occurrence and `*()` zero or more of pattern. Therefore `#` will match the 0 and do nothing. Same with `%`. Try it with `+()` and it should work as expected. – 123 Sep 12 '16 at 08:10
  • @123, why have you changed the title of this question? The `extglob` option does not exist `ksh`. – Jdamian Sep 12 '16 at 08:17
  • 1
    yours made no sense. ksh still uses extendedglob, even if the option does not exist. – 123 Sep 12 '16 at 08:20

1 Answers1

2

If you use @ instead of ? then it works as expected:

$> echo "${V#@(35|88)}"
xAB

$> echo "${V%@(xAB|Bzh)}"
35

Similarly behavior of + instead of *:

$> echo "${V#*(35|88)}"
35xAB

$>echo "${V#+(35|88)}"
xAB

It is because:

  • ?(pattern-list) # Matches zero or one occurrence of the given patterns
  • @(pattern-list) # Matches one of the given patterns

And:

  • *(pattern-list) # Matches zero or more occurrences of the given patterns
  • +(pattern-list) # Matches one or more occurrences of the given patterns
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • 3
    I think the key part here is that `#` will use the shortest possible match, which in these cases is 0 occurrences. – 123 Sep 12 '16 at 08:13
  • Right `#` indeed matches shortest possible match but behavior changes when we use `@` instead of `?` in `extglob`. – anubhava Sep 12 '16 at 08:17
  • The behaviour doesn't change, it still matches the shortest possible match. Just that `@` needs at least one occurrence. – 123 Sep 12 '16 at 08:30
  • `@ needs at least one occurrence.` yes that is what I meant – anubhava Sep 12 '16 at 08:37