Variable definition changes no Bash

2

No Bash 3.00.16, o seguinte imprime defined e no Bash 4.2.24 imprime undefined :

my_test() {
    local foo
    if [ -n "${foo+defined}" ]
    then
        echo defined
    else
        echo undefined
    fi
}
my_test

Não encontrei nada obviamente relevante na página Alterações no Bash .

  • Quando isso mudou?
  • Isso foi considerado uma correção de bug ou um efeito colateral de alguma outra alteração? Em outras palavras, o comportamento atual pode ser considerado estável?
por l0b0 04.03.2013 / 13:01

1 resposta

4

O comportamento muda do Bash 4.0 em diante e parece uma correção de bug de escopo variável. O comportamento do seu código é alterado com base na existência de variáveis globais com o mesmo nome.

Nas versões anteriores a 4.0

  • Se você tiver um variable global definido com o mesmo nome que o local, ${variable+override} funcionará conforme documentado.
  • Se você não tiver uma variável global, ${variable+override} usará o valor de substituição.

Isso é o oposto do que você normalmente esperaria de um problema de escopo global. Talvez ter as causas globais local para configurar a variável de maneira diferente em versões anteriores do Bash ou talvez + procure variáveis de uma maneira diferente.

Como o @rush mencionou, você obtém um comportamento consistente em todas as versões se usar ${foo:+defined} . Também não consegui encontrar muita documentação sobre como usar apenas o símbolo de mais, exceto as referências ao uso de ${1+"$@"} para o qual há um teste na origem. @choroba e @chepner acrescentaram que man bash explica que Omitir os resultados do cólon em um teste apenas para um parâmetro que não foi definido .

Usando a seguinte função modificada (ter a função com o mesmo nome da variável não impactou em nada, mas foi a primeira coisa que achei que poderia estar provocando o bug):

foo() {
    echo "global bar [${bar+defined}]"
    local bar
    echo "local bar  [${bar+defined}]"
}

4.0.0 (1) -release

$ echo $BASH_VERSION
4.0.0(1)-release
$ unset bar
$ foo
global bar []
local bar  []
$ bar=test
$ foo
global bar [defined]
local bar  []

3.2.0 (1) -release

$ echo $BASH_VERSION
3.2.0(1)-release
$ unset bar
$ foo
global bar []
local bar  [defined]
$ bar=test
$ foo
global bar [defined]
local bar  []

3,00.16 (1) -release

$ echo $BASH_VERSION
3.00.16(1)-release
$ unset bar
$ foo
global bar []
local bar  [defined]
$ bar=test
$ foo
global bar [defined]
local bar  []

2,05b.0 (1) -release

$ echo $BASH_VERSION
2.05b.0(1)-release
$ unset bar
$ foo
global bar []
local bar  [defined]
$ bar=test
$ foo
global bar [defined]
local bar  []
    
por 04.03.2013 / 18:08

Tags