• Uncategorized

About linux : Palindrome-checker-using-user-input-and-while-loop-in-bash

Question Detail

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

Question Answer

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.

Try this one:

#!/bin/bash

while :; do
    read -p "Enter a word: "

    if [[ ${REPLY} == "$(rev <(printf %s "${REPLY}"))" ]]; then
        echo "It is a palindrome."
        break
    fi

    echo "Not a palindrome."
done

Alternatively it can be done simpler like this but this isn’t right since theoretically “It is a palindrome.” will be still sent even if the loop breaking is not caused by correct input but other errors.

#!/bin/bash

while read -p "Enter a word: "; [[ ${REPLY} != "$(rev <(printf %s "${REPLY}"))" ]]; do
    echo "Not a palindrome."
done

echo "It is a palindrome"

By the way it uses Process Substitution.

One can create a function that reverses strings instead and that should be trivial but it’s optional scope.

First get it working.
You want to check for one argument. When the argument is given, assign it to input. Quote $input avoiding problems witch special characters and spaces. Add spaces around == to make it compare and calculate reverse again in the loop. I also used $(rev temp) what works better than backtics.

#!/bin/bash
if [ $# -ne 1 ]
then
    echo "Enter the word"
    read input
else
  input="$1"
fi
echo "$input" > temp
reverse=$(rev temp)
echo "$reverse"

while [ ! "$input" == "$reverse" ]
do
  echo "Not a palindrome"
  read input
  echo "$input" > temp
  reverse=$(rev temp)
done
echo "it is a palindrome"
rm temp

You can avoid a tmp file like this:

#!/bin/bash
if [ $# -ne 1 ]
then
    echo "Enter the word"
    read input
else
  input="$1"
fi
while [ ! "$input" == "$(rev <<< "${input}")" ]
do
  echo "Not a palindrome"
  read input
done
echo "it is a palindrome"

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.