A very small bash script challenge

by jagbir on April 25, 2012

*Kind Note*: This was written with a sense of humor to allow visitors quickly discover code anomaly and suggests fixes but if it is not up to your mark, please close your browser tab instead of making unnecessary noise. Thanks You!
I am putting a damn small thing here regarding bash script for fun.

Here it goes: Need to create a bash script which asks for a word from user, say either “one”, “two” or “three” and then check in single if statement (no else if section) that if its not “one” or “two” or “three” then print Not OK otherwise print OK.

Further, here is a snippet, check and figure out why its not working as expected:

#!/bin/bash
echo -n Enter a word:
read myword
 
if [[ $myword != "one" || $myword != "two" || $myword != "three" ]]; then
 echo Not OK
else
 echo OK
fi

Please put your suggestion/solution script in comments.

  • sandeep

    hostname$ /tmp/script
    Enter a word:hello
    OK
    hostname$ /tmp/script
    Enter a word:one
    Not OK

    is that you neeD?

  • http://whatanindianrecipe.com Pradeep

    @Jags: Fixed

    #!/bin/bash
    echo -n Enter a word:
    read myword

    if [[ $myword != "one" && $myword != "two" && $myword != "three" ]]; then
    echo Not OK
    else
    echo OK
    fi

  • http://linuxadminzone.com jagbir

    @sandeep, sorry that’s not intended :)

    @Pradeep: quick and cool. thanks :) but using && for or operation is giving an illogical feeling.. :P

  • http://linuxadminzone.com jagbir

    Friends, any other way for this.. just checking out options? :D

  • saurav yadav

    #!/bin/bash
    echo Enter a word:
    read myword
    echo Myword is: $myword
    if [ "$myword" == "one" ] || [ "$myword" == "two" ] || [ "$myword" == "three" ]
    then
    echo OK
    else
    echo NOT OK
    fi

  • Deepak

    Sir,
    Problem with your logic:
    Say the user enters-in “one”, ($myword != “one”) will be false but at the same time ($myword != “two”) and ($myword != “three”) will be true which will make the complete if statement ( having OR clause) true and thus the output as “Not Ok”

    Solution:
    1. #!/bin/bash
    echo -n Enter a word:
    read myword

    if [[ $myword != "one" && $myword != "two" && $myword != "three" ]]; then
    echo Not OK
    else
    echo OK
    fi

    2. #!/bin/bash
    echo -n Enter a word:
    read myword

    if [[ $myword == "one" || $myword == "two" || $myword == "three" ]]; then
    echo OK
    else
    echo Not OK
    fi

  • http://linuxadminzone.com jagbir

    Thanks Deepak for comment. I will check that out. :)

  • http://madmod.com Dave Mawdsley

    To consider a simpler case, study:
    if [ $myword != "one" || $myword != "two ] …

    When a person inputs: one, the second part of the test is true.
    When a person inputs: two, the first part of the test is true.
    When a person inputs: three, both parts of the test are true.

    Thus there’s no way to make the test false.

    The clearer approach and to avoid a compounded negative is:
    if [ $myword == "one" || $myword == "two" ] … which will vary between true or false depending upon the input.

  • http://linuxadminzone.com jagbir

    Thanks Dave for comment. The purpose is to print “Not OK” in If block itself, not in else block. What would be your suggestion if I want to check if the word is not one, two or three print “Not OK”, forget about else block?

  • Peter Erskine

    Answer: You need logical-AND rather than OR.
    Just change each ‘||’ to ‘&&’ and all will be well.

  • http://linuxadminzone.com jagbir

    Hi Peter, yah that’s the most suitable option.

  • David Kastrup

    Wrong tool. I don’t know _any_ version of sh that would not be fine with

    case “$reply” in
    one|two|three) echo OK;;
    *) echo not OK
    esac

    This does not call external executables (note that [ historically is a separate command, though it may be a builtin for most modern shells), and it needs nothing that would not have worked portably already 25 years ago.

  • Mouha

    This approach is a little bit different than the others. Use of grep with variables seems hackish but this script has an advantage: the block list is easy to change.

    ***

    BLOCKLIST=”
    one
    two
    three

    echo -n Enter a word:
    read MYWORD

    if [[ $(echo "$BLOCKLIST" | grep ^"$MYWORD"$) ]]; then
    echo Not OK
    else
    echo OK
    fi

  • http://linuxadminzone.com jagbir

    Mouha: What a good idea! Thanks for sharing.

    David: using case instead of if is acceptable but I want “Not OK” as first response, not in else/default as there’s nothing to do in “OK” case.

  • Steve

    read word
    case $word in
    one | two | three ) echo not ok ;;
    * ) echo ok ;;
    esac

  • Erp Derp

    Yeah, indeed, there’s a big problem with “a != x || a != y” because as soon as x != y it’ll ALWAYS be true.

    Anyway…

    If there is a case where you have nothing to do, just f*ing exit 0 and go on with anything you have to do when your condition is not matched !
    Do not, ever, imbricate code blocks when you don’t have to !

  • marsboer

    Move the ! out of the if. Then it will make sense using || and your intentions is more clear.

    #!/bin/bash
    echo -n Enter a word:
    read myword

    if ! [[ $myword == "one" || $myword == "two" || $myword == "three" ]]; then
    echo Not OK
    else
    echo OK
    fi

    Alternatively, if you want to have an array to simplify adding words to check for:

    #!/bin/bash
    VALID=( “one” “two” “three” )

    echo -n Enter a word:
    read myword

    for i in ${VALID[@]}
    do
    if [ $myword == "$i" ]; then
    echo “OK”
    exit
    fi
    done

    echo “Not OK”

  • Erp Derp

    ^ this, exactly

  • Erp Derp

    Oh, and just so you know …
    ! [[ $myword != "one" || $myword != "two" || $myword != "three" ]]
    is the same as
    [[ $myword == "one" && $myword == "two" && $myword == "three" ]]

  • Dave Mawdsley

    Here’s a methodology which might fit the bill but it doesn’t use an ‘if’ statement:

    #!/bin/bash
    echo -n “Enter a word: ”
    read myword
    case “$myword” in
    “one”)
    echo “OK”
    ;;
    “two”)
    echo “OK”
    ;;
    “three”)
    echo “OK”
    ;;
    *)
    echo “Not OK”
    ;;
    esac

  • Ken

    Your script is working as I would expect. you need to understand your Truth Tables for ANDs and ORs…
    Try replacing the ORs (||) with ANDs (&&) and it should work…

    however I would replace the whole thing with a case statement to make it usable for anything,
    just replace the echo commands with what you would want to do with the corresponding response.

    #echo -n Enter a word:
    #read myword
    #case “$myword” in
    # one)
    # echo “OK”
    # ;;
    # two)
    # echo “OK”
    # ;;
    # three)
    # echo “OK”
    # ;;
    # *)
    # echo “Not OK”
    # exit 1
    #esac

  • http://www.ubuntuhelps.com ravi

    How about new logic where you can have large array to check the conditions.

    #!/bin/bash
    echo -n Enter a word:
    read myword
    i=0
    flag=”Not OK”
    array=(one two three)
    len=${#array[*]}
    while [ "$i" -lt $len ]; do
    if [ $myword == ${array[$i]} ]; then
    flag=”OK”
    break
    fi
    let i++
    done
    echo $flag

  • Bohum

    If you want the matching to be case insensitive, try egrep:

    echo “$myword”| egrep -i ‘^one$|^two$|^three$’ >/dev/null && echo OK || echo NOT_OK

  • http://www.ubuntuhelps.com ravi

    I am back here is little correction for your script and its working..

    #!/bin/bash
    echo -n Enter a word:
    read myword

    if [[ $myword == "one" || $myword == "two" || $myword == "three" ]]; then
    echo OK
    else
    echo Not OK
    fi

  • Mike K

    This uses the newer =~ operator in [[ ]]. If you have a larger list of words to match then an array and for loop would be the way to go.

    #!/bin/bash
    echo ‘Take a one word input from the user, test if its not “one” “two” or “three”‘
    echo ‘and print “Not, OK”. Else everything OK.’
    echo
    read -p “Enter a word? ”
    if ! [[ $REPLY =~ (^one$)|(^two$)|(^three$) ]] ;then
    echo “Not, OK”
    else
    echo “OK”
    fi

  • dutchkind

    #!/bin/bash
    echo -n Enter a word:
    read myword

    if [ "$myword" != "one" -a "$myword" != "two" -a "$myword" != "three" ]
    then
    echo Not OK
    else
    echo OK
    fi

  • http://linuxadminzone.com jagbir

    Thanks friends for so many suggestions, indeed there are lots of ways to implement a single task.

  • David Kastrup

    If there is “nothing to do in first case”, nobody keeps you from doing nothing. The shell command : does nothing.

  • http://linuxadminzone.com jagbir

    Dear readers, This post is for fun but that doesn’t means if your are having an IQ of Einstein, make joke of others having written or commented something here. No one is forcing you to visit this site, and make noise if contents are not up to your taste.

    I have removed few objectionable comments which depicts how some people are full of hatred.

  • FuSnickens

    #!/bin/bash
    echo -n Enter a word:
    read myword
    if [ $myword == "one" -o $myword == "two" -o $myword == "three" ]; then
    echo OK
    else
    echo Not OK
    fi

  • Isaac

    if [[ $myword =~ ^(one|two|three)$ ]]; then echo OK; else echo Not OK; fi

  • Vincent

    [[ $1 =~ ^(one|two|three)$ ]] && echo OK ||echo Not OK

  • Isaac

    read; [[ $REPLY =~ ^(one|two|three)$ ]] && echo OK || echo Not OK

  • Isaac

    read
    unset S
    [[ ! $REPLY =~ ^(one|two|three)$ ]] && S=’Not ‘
    S+=’OK’
    echo $S

  • Durval Menezes

    My take:

    =================================================================[
    #!/bin/bash
    echo -n Enter a word:
    read myword

    if [ "X$myword" != "Xone" -a "X$myword" != "Xtwo" -a "X$myword" != "Xthree" ]; then
    echo Not OK
    else
    echo OK
    fi
    =================================================================]

    The “X” suffixing each comparison operand avoids errors when the users enters a null string.

Previous post:

Next post: