oguz ismail
oguz ismail

Reputation: 50750

Parameter expansion resulting in empty string is treated differently

Update

Someone in bug-bash mailing list has confirmed this is a bug.


If anyone's interested, a fix is available in the latest commit to devel branch.


While

bash -c 'echo "${1##*""}"' _ bar

prints an empty line,

bash -c 'echo "${1##*"${1##*}"}"' _ bar

prints bar.

I don't understand this. ${1##*} expands to an empty string, so "${1##*}" should be treated just as "" is, but seems like bash doesn't think so.

There seems to be a consensus on this among other popular sh implementations:

$ sh -c 'echo "${1##*"${1##*}"}"' _ bar

$ ash -c 'echo "${1##*"${1##*}"}"' _ bar

$ dash -c 'echo "${1##*"${1##*}"}"' _ bar

$ ksh -c 'echo "${1##*"${1##*}"}"' _ bar

$ ksh93 -c 'echo "${1##*"${1##*}"}"' _ bar

$ mksh -c 'echo "${1##*"${1##*}"}"' _ bar

$ posh -c 'echo "${1##*"${1##*}"}"' _ bar

$ yash -c 'echo "${1##*"${1##*}"}"' _ bar

$ zsh -c 'echo "${1##*"${1##*}"}"' _ bar

$

bash (with or without --posix) is the only one not conforming to that:

$ bash -c 'echo "${1##*"${1##*}"}"' _ bar
bar

And without substring processing thingies the behavior is as expected:

$ bash -c 'echo "${1##*"${1+}"}"' _ bar

$ bash -c 'echo "${1##*"${2}"}"' _ bar

$ bash -c 'echo "${1##*"${2}"}"' _ bar ''

$ 

I really wonder if there is an explanation for this, which I couldn't find in the manual. Is this a bug, or a misinterpretation of the standard? Is this behavior documented somewhere?


PS: I know a quick workaround is to unquote the inner PE, but that doesn't answer my question, and may lead to undesired results with strings containing special characters.

Upvotes: 10

Views: 381

Answers (1)

kvantour
kvantour

Reputation: 26471

This is not an answer

First I was thinking that this is due to special glob-rules, but in the end I think this is a bug in bash. The following four examples should give you a feeling why I believe this is a bug:

$ bash -c 'echo "${1##*${1%%bar}}"' _ foobar        # case 1
bar
$ bash -c 'echo "${1##*${1%%foobar}}"' _ foobar     # case 2

$ bash -c 'echo "${1##*"${1%%bar}"}"' _ foobar      # case 3
bar
$ bash -c 'echo "${1##*"${1%%foobar}"}"' _ foobar   # case 4
foobar

Case 1 and case 3 differ in the quotes. But parameter expansion of the form ${parameter##word} use pathname expansion rules to process word. So *foo and *"foo" have identical behaviour as double-quotes in pathname expansion can be ignored unless they embrace special pattern characters (*,?,...). This is seen in the following example:

$ bash -c 'echo "${1##*${2%%b*r}}"' _ 'foobar' 'f*ob*r'
bar
$ bash -c 'echo "${1##*"${2%%b*r}"}"' _ 'foobar' 'f*ob*r'
foobar

So if this is the case, why should Case 2 and Case 4 behave differently?

Upvotes: 2

Related Questions