A expansão de parâmetros que resulta em uma cadeia vazia é tratada de maneira diferente

10

Atualizar

Alguém na lista de discussão bug-festa tem confirmou este é um bug.


Se alguém estiver interessado, uma correção está disponível na confirmação mais recente para o desenvolvimento da ramificação .


Enquanto

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

imprime uma linha vazia,

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

impressões bar.

Eu não entendo isso. ${1##*}se expande para uma string vazia, então "${1##*}"deve ser tratado como ""está, mas parece que o bash não pensa assim.

Parece haver um consenso sobre isso entre outras shimplementações populares :

$ 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 (com ou sem --posix) é o único que não está em conformidade com isso:

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

E sem as coisas de processamento de substring, o comportamento é o esperado:

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

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

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

$ 

Eu realmente me pergunto se existe uma explicação para isso, que não encontrei no manual. Isso é um bug ou uma interpretação incorreta do padrão? Esse comportamento está documentado em algum lugar?


PS: Eu sei que uma solução rápida é citar o PE interno, mas isso não responde à minha pergunta e pode levar a resultados indesejados com seqüências contendo caracteres especiais.

oguz ismail
fonte
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)imprime uma cadeia vazia #
William Pursell
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)imprime "bar"
William Pursell
@William testado em 4.4.20 e 5.0.11 e ambos print "bar"
oguz ismail
Isso parece ser um problema com a expansão em geral. Na minha 4.4.12(3)-release, echo "${BASH##*"${BASH##*}"}"-> /bin/bash. Enquanto echo "\${BASH##*"${BASH##*}"}"-> ${BASH##*}e eval echo "\${BASH##*"${BASH##*}"}"-> estiver em branco.
Jeff Y

Respostas:

2

Esta não é uma resposta

Primeiro, pensei que isso se devia a regras glob especiais, mas no final acho que isso é um bug no bash. Os quatro exemplos a seguir devem lhe dar uma idéia de por que acredito que isso seja um 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

O caso 1 e o caso 3 diferem entre aspas. Mas a expansão de parâmetros do formulário ${parameter##word}usa regras de expansão de nome de caminho para processar word. Assim, *fooe *"foo"têm um comportamento idêntico ao aspas em expansão de nome pode ser ignorado a menos que eles se abraçam caracteres especiais padrão ( *, ?...). Isso é visto no seguinte exemplo:

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

Portanto, se esse for o caso, por que os casos 2 e 4 devem se comportar de maneira diferente?

kvantour
fonte
por que os casos 2 e 4 devem se comportar de maneira diferente? Não há razão, tanto ${1+}e se ${1+""}expande para cadeia vazia, mas eles não são tratados da maneira como ${1##*}é (veja minha edição mais recente). Assim, podemos deduzir que isso é um bug, certo?
oguz ismail
11
@oguzismail Exatamente! Se os casos 1 e 3 se comportarem da mesma forma, os casos 2 e 4 também deverão se comportar de forma idêntica.
kvantour