83

I'm looking for the equivalent to this JS assignment:

FOO = FOO || "I must have been falsey!";
Magnus
  • 1,002

2 Answers2

100

Either of these expansions might be what you're looking for, depending on when exactly you want to do the assignment:

Omitting the colon results in a test only for a parameter that is unset. [...]

${parameter:-word}

If parameter is unset or null, the expansion of word is substituted. Otherwise, the value of parameter is substituted.

${parameter:=word}

If parameter is unset or null, the expansion of word is assigned to parameter. The value of parameter is then substituted. Positional parameters and special parameters may not be assigned to in this way.

If you just want to set a default on first use, then:

some-command "${FOO:=default value}"
other-command "$FOO"  # both use "default value" if FOO was null/unset

If you want to be explicit about it:

FOO="${FOO:-default value}"
some-command "${FOO}"
muru
  • 72,889
9

It depends on what you mean by false. Bash doesn't have any special values for True or False, so the only "false" value is 0. Then, a variable can be set to an empty string or it can be unset.

  1. Set the variable if it isn't already set, or if it's set to NULL (\0) or the empty string:

     ## unset variable
     $ foo=${foo:="I must have been unset empty or null!"}
     $ echo "$foo"
     I must have been unset, empty, or null!
    

    $ foo="" ## set to the empty string
    $ foo=${foo:="I must have been unset, empty, or null!"} $ echo "$foo" I must have been unset, empty, or null!

  2. Set the variable if its current value is false (0):

     $ foo=0
     $ (($foo)) ||  foo="I must have been unset, empty, or null!"
     $ echo "$foo"
     I must have been unset, empty, or null!
    
terdon
  • 242,166
  • 3
    "the only "false" value is 0" -- I would go further and say that in general, there's no single falsy value or set of falsy values in the shell. For exit status codes, 0 is truthy and everything else falsy. In arithmetic contexts (e.g. (( .. )) or ? : in arithmetic expression) 0 is falsy and everything else truthy. And with e.g. [[ $var ]], the empty string (or an unset variable) is falsy, and everything else, including 0 is truthy... – ilkkachu Jun 24 '20 at 17:10
  • 1
    Also, in Bash, foo=$'\0' is the same as foo=, it sets foo to the empty string (the "null string"). Bash can't handle NUL bytes in variables. Zsh can, and there foo=$'\0'; foo=${foo:="I must have been unset!"} does not use the default value, since := only checks if the variable is unset or empty! And yeah, "I must have been unset" is wrong in all of the cases since you're checking not just for unset variables. :) – ilkkachu Jun 24 '20 at 17:12
  • @ilkkachu yes, there's no clear meaning of false, I thought I made that clear in my answer. Did I not? And yes, foo= is the same, but I like foo=$'\0' here since it's more explicit. I'm not sure why zsh is relevant here though given that the question is specifically about bash. As for the messages, yeah, I was lazy and copied the original. I'll fix that :) – terdon Jun 24 '20 at 17:24
  • well I mean that saying it like that, "only "false" value is 0" is confusing since with exit statuses -- a rather important shell context -- it's exactly the opposite. And why have foo=$'\0' and foo="" as separate cases when they're exactly the same? Doesn't that only work to hint that that NULs/zero bytes would be ok in variables in Bash, and they'd just somehow get handled in a special way in this particular case? – ilkkachu Jun 24 '20 at 17:30
  • @ilkkachu ummm... to show that it works for both? OK, I admit I thought that I could find a case where they behaved differently but I can't. I think you're right and I may as well remove that. As for exit statuses, yes that's confusing but seems like a different issue to me so I didn't want to get into it. – terdon Jun 24 '20 at 17:35