Reputation: 71
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
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
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