Parameter expansion resulting in empty string is treated differently

ogu*_*ail 9 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
Run Code Online (Sandbox Code Playgroud)

prints an empty line,

bash -c 'echo "${1##*"${1##*}"}"' _ bar
Run Code Online (Sandbox Code Playgroud)

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

$
Run Code Online (Sandbox Code Playgroud)

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

$ bash -c 'echo "${1##*"${1##*}"}"' _ bar
bar
Run Code Online (Sandbox Code Playgroud)

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 ''

$ 
Run Code Online (Sandbox Code Playgroud)

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.

kva*_*our 2

这不是答案

首先我认为这是由于特殊的 glob-rules 造成的,但最终我认为这是 bash 中的一个错误。以下四个示例应该能让您了解为什么我认为这是一个错误:

$ 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
Run Code Online (Sandbox Code Playgroud)

情况 1 和情况 3 的引号不同。但表单的参数扩展${parameter##word}使用路径名扩展规则来处理word。因此*foo, 和*"foo"具有与路径名扩展中的双引号相同的行为,可以忽略它们,除非它们包含特殊模式字符(*, ?,...)。这可以在以下示例中看到:

$ bash -c 'echo "${1##*${2%%b*r}}"' _ 'foobar' 'f*ob*r'
bar
$ bash -c 'echo "${1##*"${2%%b*r}"}"' _ 'foobar' 'f*ob*r'
foobar
Run Code Online (Sandbox Code Playgroud)

那么如果是这样的话,为什么案例 2 和案例 4 的表现会有所不同呢?