Search code examples
linuxbashloopswhile-looppalindrome

Palindrome checker using user input and while loop in bash


I'm trying to make a bash script that checks if a word is a palindrome for my homework assignment, but I can't get my while loop to work properly. The script should keep running and asking for a palindrome, until the user gives a palindrome. Can someone more experienced help me out with this and maybe explain what I did wrong.

#!/bin/bash

if [ $# -le 2 ]           
then 
    echo "Enter the word"
    read input                  
fi 
echo $input > temp         
reverse=`rev temp`     
echo $reverse              


while [ ! $input==$reverse ]
do  echo "Not a palindrome"
    read input 

done
echo "it is a palindrome"    
rm temp

Solution

  • Something like this should do:

    #!/bin/bash
    set -euo pipefail;
    
    while true; do
        echo -n "Enter the word: ";
        IFS=$'\n\t ' read -d$'\n' -r inputword restofsentence;
        if [[ -n "${inputword}" && -z "${restofsentence}" ]] ; then
            reverse="$( rev <( echo "${inputword}" ) )";
            if [[ "${reverse}" == "${inputword}" ]] ; then
                echo "it is a palindrome";
                exit 0;
            else
                echo "Not a palindrome";
                echo "";
                echo "";
            fi;
        fi;
    done;
    

    I'm not sure what function the $# (number of cli arguments) served, in your example, as you weren't using the cli arguments; so i've left that part out.


    As for what it all does:

    set -euo pipefail;
    

    Effectively enables "strict mode". Making BASH less of a shitty scripting language. It doesn't really have much of an effect in this script, but it's good practice to always have that in every script by default.

    while true; do
    

    Start a loop and keep repeating it forever.

    echo -n "Enter the word: ";
    

    The -n inhibits the usual newline at the end of the sentence.

    IFS=$'\n\t '
    

    Explicitly sets the Internal Field Separator. This means bash's interpretation of what a word is, is the input "broken apart" on newlines (\n), tab characters (\t) and spaces (' '); generally this is the default value, but its always good practise to manually set IFS either on a per-script basis, or for every read-like command.

    read -d$'\n' -r inputword restofsentence;
    

    Reads user input up to delimiter newline (-d$'\n'), meaning the enter key. Don't allow backslash-escapes -r to be used for things like multi-line input. The inputline is split into words based on the earlier IFS; after which the first word goes into inputword, and potential 2nd/3rd/...-words go into restofsentence.

    if [[ -n "${inputword}" && -z "${restofsentence}" ]] ; then
    

    We expect inputword to have a value (non-empty) and we expect restofsentence to be empty. If that is not the case, we simply let the while-loop repeat and ask for input again. This way we never deal with empty input (because inputword would be empty) nor with multi-word input (because restofsentence wouldn't be empty).

    reverse="$( rev <( echo "${inputword}" ) )";
    

    We echo the inputword into a virtual file, and pass that to the rev program, which echos the reverse value. We store that in variable reverse.

    The fact that we aren't using a real file (which is stored on the filesystem, instead of only in memory), saves us from having to clean that up later.

    if [[ "${reverse}" == "${inputword}" ]] ; then
    

    We compare if the inputword and reverse are identical, if they are then we're dealing with a palindrome.

    exit 0;
    

    Once we've had a successful palindrome, we quit (exitcode 0 indicates there was no error).


    The program (specifically the while-loop) keeps repeating forever until a successful palindrome is found.