3

I am trying to compare the string stored in a variable with three different strings and if none of them match then throw an error. I've tried to do this in a single if statement using the logical operator OR. But every time I am getting error even though the value stored in the variable is same as one of the possible value. Please find the snippets I tried.

if [[ "$TYPE" != "LOCAL" || "$TYPE" != "REMOTE" || "$TYPE" != "BOTH" ]]; then
    echo -e "\n\tINCORRECT OR NULL ARGUMENTS PASSED. PLEASE VERIFY AND CORRECT THE USAGE MENTIONED AS BELOW: \n"
    Usage
    exit 1
fi


if [[ "$TYPE" != "LOCAL" ]] || [["$TYPE" != "REMOTE" ]] || [["$TYPE" != "BOTH" ]]; then
    echo -e "\n\tINCORRECT OR NULL ARGUMENTS PASSED. PLEASE VERIFY AND CORRECT THE USAGE MENTIONED AS BELOW: \n"
    Usage
    exit 1
fi
  • 4
    you want && not || – pLumo Jul 27 '18 at 12:54
  • @RoVo I want OR because $TYPE has 3 possible values viz. LOCAL,REMOTE or BOTH and if doesn't matches with any of these 3 then it should throw error. Your suggestion please. – Mahendra Jul 27 '18 at 12:58
  • 2
    TYPE cannot simultaneously be equal to LOCAL, REMOTE, and BOTH. In plain English, your use of OR says "If type is not local, OR if type is not remote, OR if type is not both, throw an error." What you probably want is "If type is not local, AND is not remote, AND is not both, then throw an error." See the difference? – Kevin Kruse Jul 27 '18 at 13:08
  • NOT (this OR that OR theother) is equivalent to (NOT this) AND (NOT that) AND (not theother) -- this is one of De Morgan's laws of logic. – Gordon Davisson Jul 27 '21 at 10:24

1 Answers1

9

You've got your logic backward. Any string is guaranteed to be either different from LOCAL or different from REMOTE because a string cannot be LOCAL and REMOTE at the same time.

Here, the right tool for the task is a case statement (which is standard sh syntax contrary to those [[...]] ksh operators):

case $TYPE in
  (REMOTE|LOCAL|BOTH) ;; # OK
  (*) printf >&2 'Error...\n'; exit 1;;
esac

If you wanted to use [[, in ksh or bash or zsh in ksh emulation you could do:

if [[ $TYPE != @(REMOTE|LOCAL|BOTH) ]]; then
  printf >&2 'Error...\n'
  exit 1
fi

Or [[ $TYPE != REMOTE && $TYPE != LOCAL && $TYPE != BOTH ]] or [[ ! ($TYPE = REMOTE || $TYPE = LOCAL || $TYPE = BOTH) ]], etc.

Or using the standard [ command: [ "$TYPE" != REMOTE ] && [ "$TYPE" != LOCAL ] && [ "$TYPE" != BOTH ].

With ksh93, bash or zsh, another option is to use an associative array:

typeset -A allowed_TYPE
allowed_TYPE=([REMOTE]=1 [LOCAL]=1 [BOTH]=1)
if ((!allowed_TYPE[\$TYPE])); then
  printf >&2 'Error...\n'
  exit 1
fi

(the \ in \$TYPE is important to avoid introducing arbitrary command execution vulnerabilities).

With zsh, you can also use a plain array:

 allowed_TYPE=(REMOTE LOCAL BOTH)
 if ((! $allowed_TYPE[(Ie)$TYPE]))...