How does extglob work with shell parameter expansion?
Asked Answered
F

1

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

Forbear answered 12/9, 2016 at 7:55 Comment(3)
# 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.Normally
@123, why have you changed the title of this question? The extglob option does not exist ksh.Forbear
yours made no sense. ksh still uses extendedglob, even if the option does not exist.Normally
Z
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
Zee answered 12/9, 2016 at 8:9 Comment(4)
I think the key part here is that # will use the shortest possible match, which in these cases is 0 occurrences.Normally
Right # indeed matches shortest possible match but behavior changes when we use @ instead of ? in extglob.Zee
The behaviour doesn't change, it still matches the shortest possible match. Just that @ needs at least one occurrence.Normally
@ needs at least one occurrence. yes that is what I meantZee

© 2022 - 2024 — McMap. All rights reserved.