0

I'm a beginner in bash scripting, so some features aren't clear for me, for example this one below.

man bash says:

if list; then list; [ elif list; then list; ] ... [ else list; ] fi
          The  if  list  is  executed.  If its exit status is zero, the then list is executed.
          Otherwise, each elif list is executed ...

Key information for me is that exit status in if list should be 0.

I execute a command in terminal:

if [[ /usr/bin/false && 0 ]] ; then echo success ; fi

if list here is /usr/bin/false && 0 and I expect, that this command will print nothing because of /usr/bin/false, which exit status is always 1. But it prints success, as if the exit status of the /usr/bin/false && 0 command was 0!

I've checked /usr/bin/false && 0 exit status separately:

$ /usr/bin/false && 0
$ echo $?
1

Status is 1, as I expected. But I don't get why if statement above executes as if it was 0.

Boolean_Type
  • 1,146
  • 3
  • 13
  • 40
  • https://stackoverflow.com/q/26675681/4722345 – JBallin Jan 29 '23 at 01:51
  • 1
    https://stackoverflow.com/q/49849957/4722345 – JBallin Jan 29 '23 at 01:52
  • In the example you give, `list` is not `/usr/bin/false && 0`, but `[[ /usr/bin/false && 0 ]]` – William Pursell Jan 29 '23 at 01:54
  • @WilliamPursell Hmm, when I run `[[ /usr/bin/false && 0 ]]; echo $?`, I see `0`. But I'm telling you I'm a very beginner, so I don't understand, why `[[ /usr/bin/false && 0 ]]` gives us `0` and `/usr/bin/false && 0` gives `1`. Please, give a detailed answer in this post, if it is not hard for you. – Boolean_Type Jan 29 '23 at 02:03
  • 1
    The second of the links posted by JBallin is directly on point, because the person there makes the same mistake of using `[` or `[[` when they shouldn't. The answers telling that person to stop using `[[` to wrap the name of a command when they want to test the exit status of that command are exactly the answer you need here. – Charles Duffy Jan 29 '23 at 04:27
  • 1
    The other thing is that it's not clear what you expect `0` to mean. Do you want it to be true or false? If you want it to be false because it's not a positive integer, make it `(( 0 ))`. If you want to to be true because it's the specific value 0, make it `(( 0 == 0 ))`. If you want to to be true because it's not an empty string, make it `[[ 0 ]]`. – Charles Duffy Jan 29 '23 at 04:32
  • @CharlesDuffy and JBallin, I've figured it out; you were totally right and I wasn't. My question is marked as duplicated with proposition to delete, and now I cleanly understand why. Thank you for links and answers! – Boolean_Type Jan 29 '23 at 16:19

1 Answers1

3
if [[ /usr/bin/false && 0 ]] ; then echo success ; fi

The cause of your confusion is that in this context /usr/bin/false is not a command that is run, it is just a string.

The list in question is not /usr/bin/false && 0, it is [[ /usr/bin/false && 0 ]], which is [[ with some arguments.

Inside [[, there are two strings (/usr/bin/false and 0) and a control operator (&&).

As long as a string cannot be interpreted as an operator, providing a string alone is equivalent to the test -n string, which tests that a string is not zero-length.

[[ /usr/bin/false && 0 ]] == [[ -n "/usr/bin/false" && -n "0" ]]

Both /usr/bin/false and 0 are not zero-length.

Therefore the && returns 0 (true).


To have /usr/bin/false be treated as a command, you would need something like:

if /usr/bin/false && [[ 0 ]]; then echo success; fi
jhnc
  • 11,310
  • 1
  • 9
  • 26
  • 1
    Note that in `[[ 0 ]]`, the `0` isn't being treated as a number, just a meaningless string. `[[ 0 ]]`, `[[ 1 ]]`, `[[ true ]]`, `[[ false ]]`, and `[[ wibble ]]` all evaluate as true, because "0", "1", "true", etc are all non-null strings. (As opposed to `[[ "" ]]` and `[[ ]]`, which would both evaluate to false.) – Gordon Davisson Jan 29 '23 at 05:58