2

I was messing around with bash true/false, and I noticed something non-standard:

$ if $varible_i_have_never_set_before; then echo yes; fi
yes

Bash empty variables seem to evaluate to true. Usually uninitialized booleans are inherently false, at least in most modern programming languages. Is there a good explanation for this? Is there any way to get the desired functionality, short of string comparisons?

apottere
  • 303
  • 3
  • 8
  • @IgnacioVazquez-Abrams: Look at the [accepted answer](http://stackoverflow.com/a/8973170/827263); it covers the case in this question. – Keith Thompson Aug 20 '13 at 15:05
  • The first question is pretty much a duplicate, but no one has answered the second one yet. Should I ditch this sort of construct entirely or invert all my logic? Neither option sounds fun. – apottere Aug 20 '13 at 15:52
  • In many languages, using an uninitialized variable either yields an unspecified result or causes undefined behavior. The fact that `if` with an unset variable is treated as a true condition is bizarre. I suggest the solution is; don't do that. You can either set the variable to either `true` or `false` (so `if $var ; then ...` invokes the appropriate built-in command), or you can use an explicit comparison like `if [ "$var" = "true" ] ; then ...`. – Keith Thompson Aug 20 '13 at 15:57
  • Yeah, I don't want to restrict myself to always initializing booleans, because there should be no need to (and it makes the specific code I'm writing more complicated). I'll just go back to `foo="true"` or `foo=""`, and test with `if [[ $foo ]]; ...`. Thanks for the help, though. – apottere Aug 20 '13 at 16:03

2 Answers2

5

You're misunderstanding what if does. It does not check the contents of the argument, it checks the return value of the command. Since there is no value in the variable, nothing is run. And, strange as it seems, this nothing being run has a return value of 0, which if considers true.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
0

And I imagine the internal Bash function that calls commands to be like.

int call_command(char * command, char ** args, int argc)
{
    int r = 0;  ## default, should actually be just u8.
    char * external_path = 0;
    if (command) {
        if (is_function(command)) {
            r = call_function(command, args, argc);
        }
        else if (is_builtin(command)) {
            r = call_builtin(command, args, argc);
        }
        else if ((external_path = check_if_external_command_and_get_absolute_path(command))) {
            r = call_external(external_path, args, argc);
        }
        else {
            printf("bash: %s: command not found\n", command);
            r = 127;
        }
    }
    return r;
}
konsolebox
  • 72,135
  • 12
  • 99
  • 105