[Solved] BASH - chaining TEST and COMMAND with && and II

Can you explain what this line of script is doing.
What I have understood is :
-- variable C is the name of a software which is either not installed, so it must be installed or allready installed and then should be update if newer version found
-- branch B="$B $C" is to install the software
-- branch D="$D $C" is to update the software

How does [ "$A" == "0" ] && B="$B $C" || D="$D $C" works ?

A="0" or not
B=""
C="a_software-5.4.3-7.x86_64.rpm"
D=""
#
Download_the_package_and_put_it_in_tmp_directory   $C
#
if [ -f /tmp/$C ] ; then
    [ "$A" == "0" ] && B="$B $C" || D="$D $C"
else
        echo "Package not found"
fi

Help would be appreciated.

As long as the command between && and || has an exit code of 0, the construct works like an if...then...else.

But if not ...

true && false || echo oops

is not the same as

if true
then
    false
else
    echo oops
fi

Basically "&&" and "||" are logical operators, meaning "AND" and "OR".

Every command has a return value (=error level, $?) and the Unix convention is that a return value of "0" (=TRUE) means successful completion, everything else means failing for different reasons. A program might return the following values, for instance:

0     success
1     file(s) not found
127   parameter error - user gave a command line which doesn't make sense

"AND" only is true when both parts are true. "A AND B" only evaluates to true if A is TRUE AND B is TRUE, otherwise it is false. Because the programmers of these operators know this too they implemented "&&" to work this way: first run A, and if this returns FALSE there is no sense in attempting B, because the complete expression can never be TRUE, regardless of what B returns. This means in turn, that B is only attempted if A returns true.

Therefore the following two constructs are identical:

command1 && command2

if command1 ; then
     command2
fi

The same goes for "||", which is a logical OR. As it is an EXCLUSIVE OR, it is only true if exactly one of its operands are true. It is false if both are false and it is false if both are true. Therefore the system again runs the first operand and if this returns TRUE, it will not even attempt B, because the whole cannot result in TRUE any more. Only if A returns FALSE it will attempt B. In other words: the following two are equivalent:

command1 || command2

if ! command1 ; then
     command2
fi

Here is an example: we will use "cat", which returns an error level of "0" if it can display a file, but returns non-0 if the file name specified doesn't exist (or is not readable, ...).

cat /etc/passwd >/dev/null

This will display the contents of /etc/passwd to <stdout>, which is redirected to /dev/null. Basically this command will show nothing on the screen, but it will still produce a return level.

cat /etc/passwd >/dev/null; echo error level is $?
cat /some/path/blabla >/dev/null; echo error level is $?

The second file mentioned is supposed to not exist (should you happen to actually have the file "/some/path/blabla", replace it with another filename). Both commands will produce no output, but both will have different error levels.

Now we use this device with our logical operators:

cat /etc/passwd >/dev/null && echo "file /etc/passwd does exist"
cat /etc/passwd >/dev/null || echo "file /etc/passwd does not exist"
cat /some/path/blabla >/dev/null && echo "file /some/path/blabla does exist"
cat /some/path/blabla >/dev/null || echo "file /some/path/blabla does not exist"

All the first commands in each line are executed, but notice, that only the first and the fourth of the second commands are executed, depending on the existence of the mentioned files. Basically these lines are tests for the existence of the respective files, so it would have been easier to do than this. It should explain how the operators work, though.

I hope this helps.

bakunin

2 Likes

Bakunin's explanation is correct and little to add for the cases covered. But the orig. request had a construct like A && B || C . In this case, C is the "fallback" branch in case A should fail:

$ true && echo "YES" || echo "NO"
YES
$ false  && echo "YES" || echo "NO"
NO

And this is what happens in the request: Variable B collects all packages to be installed and D all packages to be updated.

1 Like

Thank you very much every body for taking time to help me.