exclamation mark to test variable is true or not in bash shell

前端 未结 3 1211
迷失自我
迷失自我 2021-01-14 05:20

I know in shell the exclamation mark can invert the outcome of condition. Here I wanna use it to test variable is true or false .

#! /bin/bash
bat=false
if [         


        
3条回答
  •  傲寒
    傲寒 (楼主)
    2021-01-14 05:52

    tl;dr

    [ ! $bar ] treats $bar as a string, and any nonempty string is considered "true" - including literal false; in other words: [ ! 'true' ] && [ ! 'false' ] both evaluate to "false", because the operands are nonempty strings in both cases and ! negates the outcome.

    Therefore, you must use string comparison:

    bar=false
    if [ ! "$bar" = 'true' ]; then  # same as: [ "$bar" != 'true' ]
        echo 'bar is false'
    else
        echo 'bar is true'
    fi
    

    In Bash, you can also use [[ ! $bar == 'true' ]] or [[ $bar != 'true' ]]; unless you need to remain POSIX-compliant, I suggest using [[ ... ]].


    In the context of [ ... ] and [[ ... ]] (Bash-specific), variable values are strings by default, and, generally, POSIX-like shells have no explicit Boolean data type.

    Unary operator ! interprets its operand implicitly as a Boolean, and a string in a Boolean context is interpreted as follows:

    • only an empty string is considered "false" (exit code 1(!))
    • any nonempty string - including literal false - is considered "true" (exit code 0(!))

    Thus, ! $bar evaluates to "false", because $bar - containing nonempty string 'false' - evaluates to "true", and ! inverts that.


    ! can also be used outside of conditionals to directly negate the success status of commands (including [).
    Since false and true also exist as command names (typically, as shell builtins), you could do the following, but do note that it only works as intended with variable values that are either the literals false or true:

    bar=false
    if ! "$bar"; then
       echo 'bar is false'
    else
       echo 'bar is true'
    fi
    

    Background information

    POSIX-like shells only have 2 basic (scalar) data types:

    • strings (by default):

      • In [ ... ] and [[ ... ]] conditionals, operators = (== in Bash),<,<=,>,>=` perform string comparison.
    • integers:

      • In [ ... ] and [[ ... ]] conditionals, distinct arithmetic operators (-eq, lt, le, gt, ge) must be used to perform numerical comparison

      • Alternatively, in an arithmetic expansion ($(( ... ))), ==, <, <=, >, >= have their usual, numeric meaning.
        In Bash, you can also use (( ... )) as an arithmetic conditional.

    Note: Per POSIX, you cannot type a variable as an integer (because there is no way to declare a shell variable), so it is only implicitly treated as one in comparisons using arithmetic operators / in arithmetic contexts.
    In Bash, however, you can declare integer variables with declare -i / local -i, but in conditionals / arithmetic contexts it is still the choice of operator / arithmetic context that determines whether the value is treated as a string or as an integer.


    Booleans in shells are expressed implicitly as exit codes, in a reversal of the usual Boolean-to-integer mapping:

    • "true" maps to exit code 0(!)
    • "false" is expressed as exit code 1(!) or any other nonzero exit code.

提交回复
热议问题