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" ];

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


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

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

  • 2
    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:

while [[ valid -eq 0 ]]; do
    read -p 'Really? > ' argument
    case "$argument" in
            : handle 'yes' cases
            : handle 'no' cases
            printf 'Invalid input "%s".  Please say "yes" or "no".\n' "$argument" 1>&2
  • 1
    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";;

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.