# A few basics with AND or OR I need some help with

I have a few problems that I seem to be stumped with. It seems to be with the logic of Bash.

``````if [ "\$argument" = "Y" -o "\$argument" = "YES" ];
then
…
fi
``````

Is there a way to create this statement without using `"\$argument"` twice? and how could I expand this to add maybe 3 or 4 answers e.g. Yup, OK

Secondly,

``````while [ "\$argument" != "Y" ] || [ "\$argument" != "YES" ] || [ "\$argument" != "N" ] || [ "\$argument" != "NO" ]; do
echo "Not a valid selection"
done
``````

I'm not sure what I'm doing wrong here but no matter the entered statement into `\$argument`, I always get `Not a valid selection` it won't accept Y, YES, N, or NO

• This is where understanding formal logic can be very helpful. For instance, you can apply one of De Morgan's laws here: `(a != b OR a != c)` is equivalent to `NOT (a = b AND a = c)`, which might make the problem more obvious. – ddawson Jul 22 at 18:33

In your example where it's always saying the answer is invalid, that's because the logic you've written has no valid truthful cases. No matter what the value of `\$argument` is, it will always not be equal to either `Y` or `YES`, as if it is one of these values, it cannot be the other.

You might want to look into a `case` statement:

``````valid=0
while [[ valid -eq 0 ]]; do
read -p 'Really? > ' argument
case "\$argument" in
Y*|y*)
valid=1
: handle 'yes' cases
;;
N*|n*)
valid=1
: handle 'no' cases
;;
*)
printf 'Invalid input "%s".  Please say "yes" or "no".\n' "\$argument" 1>&2
;;
esac
done
``````
• Bear in mind, you can also eschew the wildcards and use e. g. `YES|yes|Y|y` for the test cases so that a response of `You know what? On second thought, I'll pass` being parsed as a "yes". – DopeGhoti Jul 22 at 18:27
• Thanks that helps quite a lot, the information will help me build out further – Earthwormben Jul 22 at 18:52
``````if [ "\$argument" = "Y" -o "\$argument" = "YES" ]; then
``````

Is there a way to create this statement without using "\$argument" twice?

In standard shell, with `case`:

``````case \$argument in
Y|YES) echo "it's 'Y' or 'YES'";;
*) echo "it's something else";;
esac
``````

In Bash/Ksh/Zsh, using regexes:

``````if [[ \$argument =~ Y|YES ]]; then
...
``````

In Bash/Ksh (or Zsh with `setopt kshglob`), using Ksh-style extended globs:

``````if [[ \$argument = @(Y|YES) ]]; then
...
``````

Of course, there's various other options, like the regex `^Y(ES)?\$`, or `^[yY]` which matches anything starting with `y` or `Y` (including `yuck, no!`).

``````while [ "\$argument" != "Y" ] || [ "\$argument" != "YES" ] ...
``````

I'm not sure what I'm doing wrong here

In cases like this, it helps to work through the logic by hand. Let's say `argument` is `Y`, then `[ "\$argument" != "Y" ]` is falsy, `[ "\$argument" != "YES" ]` is truthy, so the result of the or is truthy. Repeat for other values, and you'll see at least one of the comparisons is always true.