2

I understand that ! is used to negate an if condition in Bash, but I've just seen code which takes the format:

if ! [[ CONDITION ]]; then
    SOMETHING
fi

Is there a difference between this format and the below?

if [[ ! CONDITION ]]; then
    SOMETHING
fi

I've tried to Google but haven't found anything yet about the former syntax.

0

4 Answers 4

6

for single condition they are both same:

$ if [[ ! 1 = 1 ]]; then echo true; else echo false; fi
false
$ if ! [[ 1 = 1 ]]; then echo true; else echo false; fi
false

the difference come when testing multiple conditions:

$ if  [[ ! 1 = 2 || 2 = 2 ]]; then echo true; else echo false; fi
true
$ if  ! [[ 1 = 2 || 2 = 2 ]]; then echo true; else echo false; fi
false

so outer negation has more priority on the result.

of course you can apply inner negation for whole condition, so in this case you will prefer to use a outer negation instead:

$ if  [[ ! ( 1 = 2 || 2 = 2 ) ]]; then echo true; else echo false; fi
false
1
  • That's a great explanation, thanks. So it's basically the difference between (¬A or B) and ¬(A or B), in the example you've given.
    – Lou
    Nov 18, 2020 at 13:02
1
if ! [[ CONDITION ]]; then

The first ! is from the pipeline syntax:

   A pipeline is a sequence of one or more commands separated by one of the control
   operators | or |&.  The format for a pipeline is:

          [time [-p]] [ ! ] command [ [|⎪|&] command2 ... ]

   If the reserved word ! precedes a pipeline, the exit status of that pipeline is 
   the logical negation of the exit status as described above.

Your second example:

if [[ ! CONDITION ]]; then

is an expression:

  [[ expression ]]
  Execute conditional command.

  ! EXPRESSION              True if EXPRESSION is false; else false
1

From the bash manpage:

[[ expression ]]

Return a status of 0 or 1 depending on the evaluation of the conditional expression expression.

So,

[[ condition ]]

returns 0 when the condition evaluates to "true", and 1 otherwise. The ! negates the overall result. This is logically the same as negating the overall condition inside the test.

This kind of negation is more usual when testing for the result of an external command rather than the test constructs (e.g.

if ! grep -q "pattern" file

would execute the code if the pattern is not found in the file) and thus may come from times/shells where no internal test construct existed and the [ condition ] test, which calls the test command [ (sometimes external, sometimes builtin), was used.

0

In the first the negation is done by the if. It the 2nd it is done by the [[. In the simple case this makes no difference.

However both are sometimes needed e.g.

  • if [[ ! a && b ]] the [[ needs this ability.
  • if ! ls now the if needs it.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .