Why non-equality check of one variable against many values always returns true?

前端 未结 3 1242
无人及你
无人及你 2020-11-21 04:27

I have a variable v in my program, and it may take any value from the set of values

\"a\", \"b\", \"c\", ..., \"z\"

A

3条回答
  •  甜味超标
    2020-11-21 05:28

    I figured I'd contribute an answer for Bourne shell script, since the syntax is somewhat peculiar.

    In traditional/POSIX sh the string equality test is a feature of the [ command (yes, that is a distinct command name!) which has some pesky requirements on quoting etc.

    #### WRONG
    if [ "$v" != 'x' ] || [ "$v" != 'y'] || [ "$v" != 'z' ]; then
        : some code which should happen when $v is not 'x' or 'y' or 'z'
    fi
    

    Modern shells like Ksh, Bash, Zsh etc also have [[ which is somewhat less pesky.

    #### STILL WRONG
    if [[ $v != 'x' || $v != 'y' || $v != 'z' ]]; then
        :  some code which should happen when $v is not 'x' or 'y' or 'z'
    fi
    

    We should highlight the requirement to have spaces around each token, which is something many beginners overlook (i.e. you can't say if[[$v or $v!='y' without whitespace around the commands and operators), and the apparent optionality of quoting. Failing to quote a value is often not a syntax error, but it will lead to grave undesired semantical troubles if you fail to quote a value which needs to be quoted. (More on this elsewhere.)

    The obvious fix here is to use && instead of || but you should also note that [[ typically sports support for regular expressions, so you can say something like

    if [[ ! $v =~ ^(x|y|z)$ ]]; then
        : yeah
    fi
    

    and don't forget the trusty old case statement which is quite natural for this, and portable back into the late 1970s:

    case $v in
        x | y | z)
           ;; # don't actually do anything in this switch
        *) # anything else, we fall through to this switch
           yeah
           some more yeah
           in fact, lots of yeah;;
     esac
    

    The trailing double semicolons cause aneurysms at first, but you quickly recover, and learn to appreciate, even love them. POSIX lets you put an opening parenthesis before the match expression so you don't have unpaired right parentheses, but this usage is rather uncommon.

    (This is obviously not a suitable answer for Unix shells which are not from the Bourne family. The C family of shells -- including the still somewhat popular tcsh -- use a syntax which is supposedly "C-like" but that's like being unable to tell apart Alice Cooper from the girl who went to Wonderland; and the Fish shell has its own peculiarities which I'm not even competent to comment on.)

提交回复
热议问题