23

Bash manual says:

A parameter is set if it has been assigned a value. The null string is a valid value.

...

If value is not given, the variable is assigned the null string.

Is the null string the same as ""?

Are their lengths both zero? Can both be tested by conditional expressions -z or -n which tests if the length of a string is zero or nonzero?

Tim
  • 101,790

2 Answers2

26

Yes, a null string in that context is a string of length 0 containing no byte at all. In bash:

var=
var=''
var=""
var=$''
var=$""
var=$(true) # or any command that outputs nothing or only newline
            # characters
var=`true`
var=${null_or_unset_var}
var=''""$''$""$(true)"`true`"

But also in bash, as a side effect of bash (contrary to zsh) not supporting NUL bytes in its variables (as it uses NUL-delimited C strings internally):

var=$'\0'
var=$'\u0000'
var=$'\c@'
var=$'\x00'
var=$'\0\0\0\0\0'

In all those cases, $var will be set but contain nothing (the null string). echo "${#var}" will output 0, [ -z "$var" ] will return true and printf %s "$var" will output nothing.

After unset var (but beware of the bug/misfeature of bash, mksh and yash where unset may reveal a version of $var from an outer scope instead of unsetting it if you're doing that from a function called from another function that had declared the variable local), $var has no value, null or not.

However $var still expands to nothing (to the null string) unless the nounset option is on. There are other differences between unset variables and variables assigned an empty value:

  • ${var?} triggers an error when $var is unset
  • ${var+x} expands to x if $var has any value (even null)
  • ${var-x} expands to x if $var is unset
  • [[ -v var ]] returns false if $var is unset
  • if the variable is marked for export, then var= is passed in the environment of every command if it's set, or not passed at all otherwise.
  • Would it be correct to say a shell does not have zero-length strings and setting a string to "" value will make it a null string? Also you say "$var still expands to nothing (to the null string)", but so does any non-declared variable. Do you see any difference between unset variable and variable never declared? Unset also removes variable type and "export" state. It seems more like "undeclare". Except that it behaves differently with "local" variables, which is not consistent as you too mentioned. – papo Oct 25 '20 at 15:35
  • ${parameter:+word} Use Alternate Value. If parameter is null or unset, nothing is substituted, otherwise the expansion of word is substituted. If I understand correctly, the docs are wrong here? Since for a null (empty) parameter, it does return the expanded word! – André Chalella Jan 12 '23 at 00:01
  • Looks like I missed this important paragraph just before: When not performing substring expansion, using the forms documented below (e.g., :-), bash tests for a parameter that is unset or null. Omitting the colon results in a test only for a parameter that is unset. – André Chalella Jan 18 '23 at 00:46
15

Yes. Using the test from this answer:

$ [ -n "${a+1}" ] && echo "defined" || echo "not defined"
not defined
$ a=""
$ [ -n "${a+1}" ] && echo "defined" || echo "not defined"
defined
$ b=
$ [ -n "${b+1}" ] && echo "defined" || echo "not defined"
defined

So setting the variable to "" is the same as setting it to empty value. Therefore, empty value and "" are the same.

  • I think it would be better to have a reference to the documentation, rather than a set of extensional tests to support this claim. – kirelagin Aug 06 '20 at 15:48
  • @kirelagin, I agree, but Bash manual does not define a term "null string". The closest it gets is in section 3.5.7, "Word splitting", where "" and '' are called "explicit nulls". – Alexander Batischev Aug 07 '20 at 16:11
  • 1
    It’s quite sad, but it looks like you are right indeed. I am a little surprised that shell documentation can be that ambiguous. – kirelagin Aug 24 '20 at 19:17