I am not looking for a different way to accomplish the apparent intention. I'm looking to understand why this exact syntax is not working.
[root#lvs ~]# while true;do
> echo "Would you like the script to check the second box ([y]n)?"
> read ans
> if [ "$ans" == "n" ];then
> echo
> echo "bye"
> exit
> elif [ "$ans" != "" -o "$ans" != "y" ];then
> echo "Invalid entry..."
> else
> break
> fi
> done
Would you like the script to check the second box ([y]n)? **"Should have continued"**
Invalid entry...
Would you like the script to check the second box ([y]n)? **"Should have continued"**
y
Invalid entry...
Would you like the script to check the second box ([y]n)? **"Correct behavior"**
alskjfasldasdjf
Invalid entry...
Would you like the script to check the second box ([y]n)? **"Correct behavior"**
n
bye
Here's a reference that's identical to so many others i found. I understand what it's doing, it's using the non logical's for AND and OR when everything I've read said that it should be using logical bools.
http://www.groupsrv.com/linux/about140851.html
Ok so here it is, with Nahuel's suggestion behaving how I had originally expected it to:
[root#lvs ~]# while true;do
> echo "Would you like the script to check the second box ([y]n)?"
> read ans
> if [ "$ans" = "n" ];then
> echo
> echo "bye!"
> exit
> elif [ "$ans" != "" -a "$ans" != "y" ];then
> echo "Invalid entry..."
> else
> break
> fi
> done
Would you like the script to check the second box ([y]n)?
asdfad
Invalid entry...
Would you like the script to check the second box ([y]n)?
[root#lvs ~]# while true;do
> echo "Would you like the script to check the second box ([y]n)?"
> read ans
> if [ "$ans" = "n" ];then
> echo
> echo "bye!"
> exit
> elif [ "$ans" != "" -a "$ans" != "y" ];then
> echo "Invalid entry..."
> else
> break
> fi
> done
Would you like the script to check the second box ([y]n)?
y
[root#lvs ~]# while true;do
> echo "Would you like the script to check the second box ([y]n)?"
> read ans
> if [ "$ans" = "n" ];then
> echo
> echo "bye!"
> exit
> elif [ "$ans" != "" -a "$ans" != "y" ];then
> echo "Invalid entry..."
> else
> break
> fi
> done
Would you like the script to check the second box ([y]n)?
n
logout
The problem is that : [ "$ans" != "" -o "$ans" != "y" ] is always true because of the or and the negation. $ans cannot be equal to "" and to "y".
Try replace these lines
if [ "$ans" == "n" ];then
elif [ "$ans" != "" -o "$ans" != "y" ];then
by these
if [ "$ans" = "n" ];then
elif [ "$ans" != "" -a "$ans" != "y" ];then
or these
if [[ $ans == n ]];then
elif [[ $ans != "" && $ans != y ]];then
The easier is to do is a case:
case $ans in
y) echo "yes"
;;
n) echo "no"
;;
*)
;;
esac
also break must be used only in a for or while loop, or in a select but it is missing in your post .
I don't really understand, why do you use -o in the elif. I would use "||" or "OR" operator. When you use two conditions in if, you should use double [[ and ]].
So if you use:
elif [[ "$ans" != "" || "$ans" != "y" ]];then
it works fine.
also logically its a flawed way of doing things.
firstly using case would be best in this scenario, secondly you are looking for == n then stating if it is blank or not equal to yes - so although no is caught out in first if statement in theory it would still meet second criteria
surely the most logical way to ensure input is 100% would be
if [ "$ans" == "n" ];then
echo
echo "bye"
exit
elif [ "$ans" == "y" ];then
echo Yes
break;
else
echo "Invalid entry... >$ans<"
fi
Related
#!/bin/sh
#datafile
#script
while echo enter name
read -r code
do
if [ "$code" = 'STOP' ];
then
break
else
grep "$code" datafile > outputres
while echo ' Would you like to see B OR R'
read -r answer
do
if [[ "$answer" = 'B' && "$code" = datafile ]];
then
echo show B.
break
elif [[ "$answer" = 'R' && "$code" = datafile ]];
then
echo show R
break
elif [[ "$answer" = 'B' && "$code" != datafile ]];
then
echo No such THING.
break
elif [[ "$answer" = 'R' && "$code" != datafile ]];
then
echo No such THING.
break
else :
echo Enter only B or R.
fi
done
fi
done
echo Goodbye!
Hello, I hope someone can help. but I'm having some issues when I execute my program I receive "no such thing" when it should display "show r".
UPDATE: I changed code to a number found in the data and it works, so I need a better way to say ("$code" = filename) number is in data or not in the data.
btw I have also checked if i have any errors and I dont
I have this bash script that receives me the error mentioned below. Do you have any explanations?
#! /bin/bash
first=1
second=1
result=2
contor=2
fib()
{
contor=$1
if [ $contor -eq $n ]
then
echo result
else
let $contor++
let result=$first+$second
first=$second
second=$results
fib $contor
fi
}
read n
result=$(fib 2)
echo $reusult
I see at least three problems here:
let $contor++ will actually substitute the value of contor, meaning the expression will be something like let 42++, which is invalid. Get rid of the $.
second=$results will set second to something other than what's in result, which will probably cause an issue when you try to execute let result=$first+$second. Use the correct variable name.
You print the variable reusult at the end, again a mis-spelling.
The way I found those issues is the same way you (or anyone, for that matter) should be finding them in bash, by temporarily putting the following lines at the top of your script to aid debugging:
set -e # stop on error
set -x # echo each interpreted line before execution.
There's are a great help when trying to figure out where the problems lie.
For what it's worth, Fibonacci is usually a bad candidate for recursion since you generally have to calculate things more than once.
That's because calculating fib(1000) as fib(999) + fib(998) usually entails a massive duplication of effort on either side of that + symbol.
That's not actually the case with your code because, while the code is calling itself, the leakage of information across levels really makes it an iterative solution - at no stage are you getting the result of fib(n-1) and fib(n-2) to calculate fib(n).
So, since you have an iterative solution anyway, you may as well remove the last vestiges of recursion and use something like:
#! /bin/bash
fib() {
# Validate input argument to be integer 1...92.
num=$1
if [[ ! ${num} =~ ^[1-9][0-9]*$ ]] ; then
echo "Invalid input '${num}'."
return
fi
if [[ ${num} -gt 92 ]] ; then
echo "Invalid input '${num}'."
return
fi
# First two Fib's are both one.
if [[ ${num} -le 2 ]] ; then
echo "1"
return
fi
# For other Fib's, just iterate keeping previous two.
grandparent=1 ; parent=1 ; child=2
((num -= 3))
while [[ ${num} -gt 0 ]] ; do
((grandparent = parent))
((parent = child))
((child = grandparent + parent))
((num--))
done
echo ${child}
}
# Rather rudimentary test harness.
[[ "$(fib x)" != "Invalid input 'x'." ]] && echo Fail A && exit
[[ "$(fib -7)" != "Invalid input '-7'." ]] && echo Fail B && exit
[[ "$(fib 0)" != "Invalid input '0'." ]] && echo Fail C && exit
[[ "$(fib 93)" != "Invalid input '93'." ]] && echo Fail D && exit
[[ "$(fib 1)" != "1" ]] && echo Fail E && exit
[[ "$(fib 2)" != "1" ]] && echo Fail F && exit
[[ "$(fib 3)" != "2" ]] && echo Fail G && exit
[[ "$(fib 4)" != "3" ]] && echo Fail H && exit
[[ "$(fib 5)" != "5" ]] && echo Fail I && exit
[[ "$(fib 6)" != "8" ]] && echo Fail J && exit
[[ "$(fib 20)" != "6765" ]] && echo Fail K && exit
[[ "$(fib 50)" != "12586269025" ]] && echo Fail L && exit
[[ "$(fib 92)" != "7540113804746346429" ]] && echo Fail M && exit
# User test.
read -p "Which Fibonacci number (>= 1)? " n
result=$(fib $n)
echo $result
You'll notice the input is restricted to the range 1..92. That's because, at some point (92 is the last one that works for me), bash will start giving strange results because of limits of its internal data types.
I have just started learning to write bash scripts. This a simplified form of what I want to write.
The problem is despite of the input, it prints only "YES".
#! /usr/bin/bash
read input
if (("$input"== "y" || "$input" == "Y"))
then
echo "YES";
elif (("$input" == "n" || "$input" == "N"))
then
echo "NO";
else
echo "Not a valid input!!"
fi
Use [[ instead of (( like,
if [[ "$input" == "y" || "$input" == "Y" ]]
and also there must be a space exists before == operator.
ie,
input="n"
if [[ "$input" == "y" || "$input" == "Y" ]]
then
echo "YES";
elif [[ "$input" == "n" || "$input" == "N" ]]
then
echo "NO";
else
echo "Not a valid input!!"
fi
You could use regular expression also for condition checking purpose.
if [[ "$input" =~ ^[yY]$ ]]
then
echo "YES";
elif [[ "$input" =~ ^[nN]$ ]]
then
echo "NO";
else
echo "Not a valid input!!"
fi
When you automaticly convert the input to lowercase (using typeset), you do not have to bother with the the uppercases.
When you use an elif, always think 10 seconds for another solution. In this case you might want to use a "switch", in shell written as a case-statement:
#!/usr/bin/bash
typeset -l input
read input
case ${input} in
"y") echo "Yes";;
"n") echo "NO";;
*) echo "Not a valid input!!";;
esac
I'm having an issue getting a a simple y/n question to work. Consider the following code:
echo "Hi there"
read ans
if [[ $ans != "y" || $ans != "Y" || $ans != "YES" || $ans != "yes" ]]; then
echo "Foo"
exit 0
fi
I've looked at – I would argue – some of the more informative answers on StackOverflow for advice: Simple logical operators in Bash
I've tried all different types of variations such as:
if [[ ($ans != "y" || $ans != "Y" || $ans != "YES" || $ans != "yes") ]]; then
echo "Foo"
exit 0
fi
if [[ ($ans != "y*" || $ans != "Y*" || $ans != "YES*" || $ans != "yes*") ]]; then
echo "Foo"
exit 0
fi
if [[ ($ans != "y") || ($ans != "Y") || ($ans != "YES") || ($ans != "yes") ]]; then
echo "Foo"
exit 0
fi
Regardless of why I type in any of these cases, it automatically fails and I'm not sure why. If anyone has a better way to handle y/n answers then please let me know! Ideally I would like to use pattern matching (like I might do with Perl) but I'm not entirely sure the best way/most efficient way to accomplish a simple y/n question.
You need to use && instead of ||. As it stands you're saying if it's not equal to any of those possibilities, then execute the "then" block. You mean to say if it's not equal to all of them, then execute the "then" block. That requires &&.
You can use:
echo "Hi there"
read ans
case "$ans" in
y|Y|YES|yes)
;;
*)
echo "Foo"
exit 0
;;
esac
The logic needs to be adjusted:
echo "Hi there"
read ans
if ! [[ "$ans" == "y" || "$ans" == "Y" || "$ans" == "YES" || "$ans" == "yes" ]]; then
echo "Foo" # User answered no
exit 0
fi
The will echo "Foo" only if the answer was not one of "y", "Y" or "YES". By contrast, consider the original logic:
[[ $ans != "y" || $ans != "Y" || $ans != "YES" || $ans != "yes" ]]
At least one of these tests will be true regardless of what the user's answer is.
Using the case statement
You might consider using the case statement to analyze the user's answer:
read -p "Hi there: " ans
case "$ans" in
[yY]*) ;;
[nN]*) echo "Foo" ; exit 0 ;;
*) echo "You were supposed to answer yes or no" ;;
esac
Try read ans, not read $ans.
I'm trying to write a script which will read two choices, and if both of them are "y" I want it to say "Test Done!" and if one or both of them isn't "y" I want it to say "Test Failed!"
Here's what I came up with:
echo "- Do You want to make a choice?"
read choice
echo "- Do You want to make a choice1?"
read choice1
if [ "$choice" != 'y' ] && [ "$choice1" != 'y' ]; then
echo "Test Done!"
else
echo "Test Failed!"
fi
But when I answer both questions with "y" it's saying "Test Failed!" instead of "Test Done!". And when I answer both questions with "n" it's saying "Test Done!"
What have I done wrong?
You are checking for the wrong condition.
if [ "$choice" != 'y' ] && [ "$choice1" != 'y' ];
The above statement is true when choice!='y' and choice1!='y', and so the program correctly prints "Test Done!".
The corrected script is
echo "- Do You want to make a choice ?"
read choice
echo "- Do You want to make a choice1 ?"
read choice1
if [ "$choice" == 'y' ] && [ "$choice1" == 'y' ]; then
echo "Test Done !"
else
echo "Test Failed !"
fi
The program is doing exactly what you told it to do. You said "If the first choice is not equal to 'y' and the second choice is not equal to 'y' then print "Test Done !" otherwise print "Test Failed !" -- so only if both choices are not y will "Test Done !" be printed.
You probably meant:
echo "- Do You want to make a choice ?"
read choice
echo "- Do You want to make a choice1 ?"
read choice1
if [ "$choice" == 'y' ] && [ "$choice1" == 'y' ]; then
echo "Test Done !"
else
echo "Test Failed !"
fi
I changed != not equals to == equals. Now only if you answer "y" to both questions will "Test Done !" be printed.
if [ "$choice" != 'y' -a "$choice1" != 'y' ]; then
echo "Test Done !"
else
echo "Test Failed !"
fi
You got the comparison logic backwards; from your description you wanted to say
if [ "$choice" = 'y' ] && [ "$choice1" = 'y' ]; then
I'm actually surprised that the && construct works, although on further inspection it probably should. Still, I would write it as
if [ "$choice" = 'y' -a "$choice1" = 'y' ]; then
You have your logic reversed; you're checking for != when you should be checking for ==. Try this:
if [ "$choice" == 'y' ] && [ "$choice1" == 'y' ]; then
echo "Test Done !"
else
echo "Test Failed !"
fi
Another thought,
$ c1='y' ; c2='y' ; [[ ${c1} = 'y' ]] && [[ ${c2} = 'y' ]] && echo true || echo false
true
$ c1='n' ; c2='y' ; [[ ${c1} = 'y' ]] && [[ ${c2} = 'y' ]] && echo true || echo false
false
$ c1='n' ; c2='y' ; [[ ${c1} = 'y' ]] || [[ ${c2} = 'y' ]] && echo true || echo false
true
$ c1='n' ; c2='n' ; [[ ${c1} = 'y' ]] || [[ ${c2} = 'y' ]] && echo true || echo false
false
$
Overflow of gibberish. (;
Try:
if [[ "$choice" != 'y' && "$choice1" != 'y' ]]; then
echo "Test Done!"
else
echo "Test Failed!"
fi
The line
if [ "$choice" != 'y' ] && [ "$choice1" != 'y' ]; then
tests if both choices aren't 'y', so when both choices are 'y', the statement is false and your program correctly prints "Test Failed".