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
CodePudding user response:
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 echo
s 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.
CodePudding user response:
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.
CodePudding user response:
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"