What's the difference between if ! [[ foo ]] and if [[ ! foo ]] in Bash?

What's the difference between if ! [[ foo ]] and if [[ ! foo ]] in Bash?

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.

答案1

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

答案2

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

答案3

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.

答案4

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.

相关内容