Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parameter expansion resulting in empty string is treated differently

Tags:

bash

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.

like image 247
oguz ismail Avatar asked Oct 30 '19 10:10

oguz ismail


1 Answers

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?

like image 96
kvantour Avatar answered Nov 14 '22 16:11

kvantour