Alexey Mukhin
Alexey Mukhin

Reputation: 71

bash empty string/command

I found some strange thing in bash and I can't understand how it works.

[test ~]$ a=""
[test ~]$ $a && echo 1
1

[test ~]$ $a
[test ~]$ echo $?
0

Why does $a (which is empty) return 0? Is it somehow transformed to empty command? If I add quotes or write empty string before &&, it will return error. While empty command returns 0.

[test ~]$ "$a" && echo 1
-bash: : command not found

[test ~]$ "" && echo 1
-bash: : command not found

[test ~]$ `` && echo 1
1

So, what is happening when I type $a?

Upvotes: 5

Views: 10084

Answers (2)

Kent
Kent

Reputation: 195089

a=""

or

a="                       " #a long empty string

then

$> $a

will return 0

$> $noExistVar

will also return 0.

They get "executed", in fact, nothing gets executed. same as you press enter or pressing 10 spaces then enter, you get return code 0 too.

$>       && echo 1

this will fail, because bash will try to execute the first part, in this case it is missing.

$> $notExistVar && echo 1

Here it works, I guess bash found the first part the $whatever, therefore no syntax error. Then "execute" it, well nothing to execute, return 0, (same as pressing enter after prompt), then check, if first part returned 0, exec the cmd after &&.

I said guess because I didn't check bash's source codes. Please correct me if it is wrong.

the $> " " && echo 1 case, I think it is clear, don't need to explain.

Upvotes: 0

DevSolar
DevSolar

Reputation: 70293

You seem to confuse bash with some other programming language. Variables get replaced, then what is left gets executed.

"$a"

This is the content of a, between quotation marks. a is empty, so this is equivalent to:

""

That is not a command. "Command not found." As there was an error, the execution was not successful (shell return code is not 0), so the second half of the command -- && echo 1 -- does not get executed.

Backticks...

``

...execute whatever is between them, with the output of that command replacing the whole construct. (There is also $() which does the same, and is less prone to being overlooked in a script.) So...

`echo "foo"`

...would evaluate to...

foo

...which would then be executed. So your...

``

...evaluates to...

 <empty>

...which is then "executed successfully" (since there is no error).

If you want to test the contents of a, and execute echo 1 only if a is not empty, you should use the test command:

test -n "$a" && echo 1

There is a convenient alias for test, which is [, which also conveniently ignores a trailing ]...

[ -n "$a" ] && echo 1

...and a bash-ism [[ that "knows" about variable replacement and thus does not need quotation marks to avoid complaining about a missing argument if $a does indeed evaluate to empty...

[[ -n $a ]] && echo 1

...or, of course, the more verbose...

if [[ -n $a ]]
then
    echo 1
fi

Ah. Missed the core part of the question:

$a && echo 1

This is two statements, separated by &&. The second statement only gets executed if the first one executes OK. The bash takes the line apart and executes the first statement:

$a

This is...

<empty>

...which is "successful", so the second statement gets executed. Opposed to that...

&& echo 1

...is a syntax error because there is no first statement. ;-) (Tricky, I know, but that's the way this cookie crumbles.)

Upvotes: 5

Related Questions