Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

In Bash 3.00.16, the following prints defined, and in Bash 4.2.24 it prints undefined:

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

I couldn't find anything obviously relevant on the Bash changes page.

  • When was this changed?
  • Was this considered a bug fix, or a side effect of some other change? In other words, can the current behavior be considered stable?
share|improve this question
    
I don't quite know the answer to your questions (when and why the change), but what I do know is that the vast majority of Linux distributions (what are you using, by the way?) now use bash 4.x . –  schaiba Mar 4 '13 at 12:13
    
@l0b0 By the way, there is notice at page on your link, that article is an incomplete overview. Moreover, I've found nothing about ${foo+defined} construction in man. There is only ${foo:+defined} which works the same way in both versions. –  rush Mar 4 '13 at 14:26
1  
@rush: The man page has a very brief sentence about the colon with these operators: "Omitting the colon results in a test only for a parameter that is unset". This behavior exists in 3.2; I don't know if it is earlier as well. This is defined in POSIX as well: pubs.opengroup.org/onlinepubs/009695399/utilities/… –  chepner Mar 5 '13 at 21:01

1 Answer 1

up vote 4 down vote accepted

The behaviour changes from Bash 4.0 onwards and it looks like a variable scope bug fix. The behaviour of your code changes based on the existence of global variables of the same name.

In versions prior to 4.0

  • If you have a global variable defined with the same name as the local, ${variable+override} will work as documented.
  • If you don't have a global variable, ${variable+override} will use the override value.

That's kind of the opposite of what you would normally expect of a global scope issue. Maybe having the global causes local to set up the variable differently in earlier versions of Bash or maybe + looks up variables in a different manner.

As @rush mentioned, you get consistent behaviour in all versions if you use ${foo:+defined}. I couldn't find much documentation on using just the plus symbol either, except for references to using ${1+"$@"} which there is a test for in the source. @choroba and @chepner added that man bash explains that Omitting the colon results in a test only for a parameter that is unset.

Using the following modified function (having the function named the same as the variable did not impact anything, but it was the first thing I thought might be triggering the 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  []
share|improve this answer
    
Excellent answer! I was hoping to avoid :+ because of the semantic difference, but it looks like it's unfeasible for now. –  l0b0 Mar 5 '13 at 16:26
    
man bash mentions omitting the colon: When not performing substring expansion, using the forms documented below, bash tests for a parameter that is unset or null. Omitting the colon results in a test only for a parameter that is unset. –  choroba Mar 8 '13 at 21:14

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.