How to combine AND and OR condition in bash script for if condition? How to combine AND and OR condition in bash script for if condition? unix unix

How to combine AND and OR condition in bash script for if condition?


The immediate problem with your statement is one of logic: you probably meant to write:

if [ "$#" -ne 1 ] || ! ([ "$1" = "ABC" ] || [ "$1" = "DEF" ] || [ "$1" = "GHI" ] || [ "$1" = "JKL" ]) then  echo "Usage: ./myscript.sh [ABC | DEF | GHI | JKL]" >&2  exit 1fi

That is: abort, if either more than 1 argument is given OR if the single argument given does NOT equal one of the acceptable values.

Note the ! to negate the expression in parentheses and the use of the POSIX-compliant form of the string equality operator, = (rather than ==).

However, given that you're using Bash, you can make do with a single [[ ... ]] conditional and Bash's regular-expression matching operator, =~:

if [[ $# -ne 1 || ! $1 =~ ^(ABC|DEF|GHI|JKL)$ ]] then  echo "Usage: ./myscript.sh [ABC | DEF | GHI | JKL]" >&2  exit 1fi

If POSIX compliance is not required, [[ ... ]] is preferable to [ ... ] for a variety of reasons.In the case at hand, $# and $1 didn't need quoting, and || could be used inside the conditional.

Note that =~ as used above works in Bash 3.2+, whereas the implicit extglob syntax used in anubhava's helpful answer requires Bash 4.1+;
in earlier versions you can, however, explicitly enable (and restore to its original value after) the extglob shell option: shopt -s extglob.


BASH actually allows use of extended glob inside [[ ... ]] and have && inside as well.

So you can do:

if [[ $# -ne 1 && $1 == @(ABC|DEF|GHI|JKL) ]]; then   echo "Usage: ./myscript.sh [ABC | DEF | GHI | JKL]"   exit 1fi


A few things:

  • [...] in bash is equivalent to the same test command (check the man page), so those && and || are not logical operators, but rather the shell equivalents
  • Parentheses in POSIX shell are not a grouping operator. They will work here, but they open a subshell, you are better off using standard test options of -a and -o (making your if statement if [ "$#" -ne 1 -a \( "$1" == "ABC" -o "$1" == "DEF" -o "$1" == "GHI" -o "$1" == "JKL" \) ], though based on your logic, it sounds like you actually want something like if [ "$#" -ne 1 -o \( "$1" != "ABC" -a "$1" != "DEF" -a "$1" != "GHI" -a "$1" != "JKL" \) ]. You probably can get better results with a case statement like follows:

usage() {    echo "Usage: ./myscript.sh [ABC | DEF | GHI | JKL]"}if [ "$#" -ne 1 ] then    usage    exit 1ficase "$1" in    ABC)        echo "Found ABC"        ;;    DEF)        echo "Found DEF"        ;;    GHI)        echo "Found GHI"        ;;    JKL)        echo "Found JKL"        ;;    *)        usage        exit 1        ;;esac

If you want to pass a set of possible static arguments in, you might want to look at the getopts special shell command.