Can anyone help me with my code? When I run my script I always get Grade F.
#!/bin/bash
echo "Enter your percentage to see grade letter"
read grade
if [ $grade -ge 60 ]; then
echo "Your Grade F"
elif [ $grade -ge 60 ] || [ $grade -le 69 ]; then
echo "Your grade D"
elif [ $grade -ge 70 ] && [ $grade -le 79 ]; then
echo "Your grade C"
elif [ $grade -ge 80 ] && [ $grade -le 89 ]; then
echo "Your grade B"
elif [ $grade -ge 90 ] && [ $grade -le 100 ]; then
echo "Your Grade is A"
else
echo "try again"
fi
You have a logic error in your code. Your first test is wrong. It tests all values that are greater than or equal to 60, and makes them an F. This prevents the rest of the tests from happening for those values.
Your second test is also wrong; you're using an OR (||) instead of an AND (&&).
Your last test could be reduced, because all values greater than or equal to 90 are an A, so the second test isn't necessary.
I personally would test for the higher vales and work down if I was writing the code, but that's your choice. The below should work.
#!/bin/bash
echo "Enter your percentage to see grade letter"
read grade
if [ $grade -le 59 ]; then
echo "Your Grade F"
elif [ $grade -ge 60 ] && [ $grade -le 69 ]; then
echo "Your grade D"
elif [ $grade -ge 70 ] && [ $grade -le 79 ]; then
echo "Your grade C"
elif [ $grade -ge 80 ] && [ $grade -le 89 ]; then
echo "Your grade B"
elif [ $grade -ge 90 ]; then
echo "Your Grade is A"
else
echo "try again"
fi
An alternative method using case statement could be
read -r -p 'Enter your percentage to see grade letter: ' percent
case $percent in
[0-9] | [0-5][0-9] ) echo 'Your Grade F';;
6[0-9] ) echo 'Your Grade D';;
7[0-9] ) echo 'Your Grade C';;
8[0-9] ) echo 'Your Grade B';;
9[0-9] | 100 ) echo 'Your Grade A';;
*) echo 'Try again'
esac
Here's how I'd do it.
#!/bin/bash
# Get the grade
read -rp "Enter your percentage to see grade letter: " grade
# Test the input to make sure it's a number,
# and exit with an error message if it isn't
[[ "$grade" =~ ^[0-9]+$ ]] || { echo "Please enter an integer." ; exit; }
# Test the number, print the grade, and exit
[[ "$grade" -le 49 ]] && { echo "You want to go home and re-think your life." ; exit; }
[[ "$grade" -le 59 ]] && { echo "Your Grade: F" ; exit; }
[[ "$grade" -le 69 ]] && { echo "Your grade: D" ; exit; }
[[ "$grade" -le 79 ]] && { echo "Your grade: C" ; exit; }
[[ "$grade" -le 89 ]] && { echo "Your grade: B" ; exit; }
[[ "$grade" -ge 90 ]] && { echo "Your Grade: A" ; exit; }
I'm not sure if it's more or less efficient than using if-elif-fi or case. I'm sure it's not as pretty. But it only tests $grade until it gets a hit and then it stops, and something about that appeals to me.
I was tempted to put the "Is this a number?" test in a loop so you wouldn't have to invoke the script again if you flubbed the input, but I resisted the temptation.
(I'm a rookie with bash scripting, so I welcome criticism.)
Related
Im trying to get an array from grades.txt, and determine what letter grade it should be assigned.
I either get
hw4part2.sh: line 26: [: : integer expression expected
If i use -ge or
hw4part2.sh: line 26: [: : unary operator expected
If i use >=
Below is the code im trying to get working
mapfile -t scores < grades.txt
numOScores=0
numOA=0
numOB=0
numOC=0
numOD=0
numOF=0
DoneWScores=0
A=90
B=80
C=70
D=60
F=59
while [ $DoneWScores -eq 0 ]
do
numOScores=$((numOScores + 1))
if [ "${scores[$numOScores]}" -ge "$A" ]
then
echo "A"
elif [ "${scores[$numOScores]}" -ge "$B" ]
then
echo "B"
elif [ "${scores[$numOScores]}" -ge "$C" ]
then
echo "C"
elif [ "${scores[$numOScores]}" -ge "$D" ]
then
echo "D"
elif [ "${scores[$numOScores]}" -le "$F" ]
then
echo "F"
else
echo "Done/error"
DoneWScores=1
fi
done
If anyone knows what my problem is, that'd be greatly appreciated
Consider this:
#!/usr/bin/env bash
if (( ${BASH_VERSINFO[0]} < 4 )); then
echo "Bash version 4+ is required. This is $BASH_VERSION" >&2
exit 1
fi
letterGrade() {
if (( $1 >= 90 )); then echo A
elif (( $1 >= 80 )); then echo B
elif (( $1 >= 70 )); then echo C
elif (( $1 >= 60 )); then echo D
else echo F
fi
}
declare -A num
while read -r score; do
if [[ $score == +([[:digit:]]) ]]; then
grade=$(letterGrade "$score")
(( num[$grade]++ ))
echo "$grade"
else
printf "invalid score: %q\n" "$score"
fi
done < grades.txt
for grade in "${!num[#]}"; do
echo "$grade: ${num[$grade]}"
done | sort
Hello here is my primary script. The test2.sh is just an echo "it worked"
what happens when I try and call from the original loop, it gets to the correct file then echo's infinite "it worked" where it should just be doing it once.
Any idea why? I really want to have another loop called outside of the main script that won't interfere, but still learning bash =P
#!/bin/bash
number=1
while true
do
if [ "$number" -eq "1" ]; then
echo "hello 1!"
elif [ "$number" -eq "2" ]; then
echo "hello 2!"
elif [ "$number" -eq "3" ]; then
echo "hello 3!"
elif [ "$number" -eq "4" ]; then
./test2.sh & continue
fi
sleep 5
((number++))
echo $number
done
first observation & is not a logical operator, & runs the precedding command in the background. Use && for logical operations.
what you need is a break keyword not a continue keyword . If you use the break keyword, the loop will stop executing. The continue keyword only rexecutes the loop , and since number is 4 , this branch of code will always run elif [ "$number" -eq "4" ]; then
working code
#!/bin/bash
number=1
while true
do
if [ "$number" -eq "1" ]; then
echo "hello 1!"
elif [ "$number" -eq "2" ]; then
echo "hello 2!"
elif [ "$number" -eq "3" ]; then
echo "hello 3!"
elif [ "$number" -eq "4" ]; then
./test2.sh && break
fi
sleep 5
((number++))
echo $number
done
or you can do this
for number in {1..4};do
(( number == 4 )) && ./test2.sh || echo "$number"
sleep 5
done
I am trying to write a script that will continue to prompt a user to enter a grade, until the user enters 999.
If the user enters 90 or more, echo A. If the user enters 80 or more, echo B. If the user enters 70 or more, echo C. Otherwise echo Failed.
I am thinking this needs a WHILE script. Below is my current code
#!/bin/bash
# Asuume that the first paramter is going to be a grade
if [ $# -lt 1 ];
then
echo -n "Please pass a a grade "
fi
gr=$1
if [ $gr -ge 90 ]
then
echo "A"
elif [ $gr -ge 80 ]
then
echo "B"
elif [ $gr -ge 70 ]
then
echo "C"
else
echo "Failed"
fi
exit 0
The script prompts me, but closes after I enter 1 grade.
Thanks in advance
As you want to prompt the user to input grades until he enters 999, you should use read instead of command line arguments. As bash doesn't have a do-while loop, we can emulate it's behavior using while as shown below:
#!/bin/bash
read -p "Please pass a grade " gr
while [ $gr -ne 999 ]; do
if [ $gr -ge 90 ]
then
echo "A"
elif [ $gr -ge 80 ]
then
echo "B"
elif [ $gr -ge 70 ]
then
echo "C"
else
echo "Failed"
fi
read -p "Please pass a grade " gr
done
exit 0
That's not a prompt, it's just a message.
Prompting would be:
read -p "Please pass a grade: " gr
But this get's into conflict with your following gr=$1, so put this into an else block:
if [ $# -lt 1 ]
then
read -p "Please pass a grade: " gr
else
gr=$1
fi
Note that you don't need a semicolon at the line end; it's the line break, which can be substituted by the semicolon.
And you don't need an exit to end a script, if you don't want to exit prematurely.
Please try below code.
while true
do
read -p "Please pass a grade:" gr
if [ ${gr} -eq 999 ]
then
exit 0
elif [ ${gr} -ge 90 ]
then
echo "A"
elif [ ${gr} -ge 80 ]
then
echo "B"
elif [ ${gr} -ge 70 ]
then
echo "C"
else
echo "Failed"
fi
done
Hi I'm creating an archiving system in bash with a long and messy if statement which doesn't currently work with the current errors being on the last few lines with the else if statement. Although I expect there are further errors with this statement anyway. The variable choice is from a menu which displays in the terminal. So if they select option 1 the user then has to enter data to be written to the crontab file.
if [ $choice -eq "1" ] then
echo "Enter the MINUTE"
read minute
if [ $minute -eq 0 ] then
GLOBIGNORE=*
minute="*"
echo minute
fi
echo "Enter the Hour"
read hour
if [ $hour -eq 0 ] then
GLOBIGNORE=*
hour="*"
echo hour
fi
echo "Enter the Day"
read day
if [ $day -eq 0 ] then
GLOBIGNORE=*
day="*"
echo day
fi
echo "Enter the Month"
read month
if [ $month -eq 0 ] then
GLOBIGNORE=*
month="*"
echo month
fi
echo "Enter the weekday"
read weekday
if [ $weekday -eq 0 ] then
GLOBIGNORE=*
weekday="*"
echo weekday
fi
echo $minute $hour $day $month $weekday " date > ~/testcron.log" > testcron.txt fi
elif [ $choice -eq "2" ]
then
echo "Enter the Source and Destination Locations"
fi
There are several issues with your code:
if [ $hour -eq 0 ] then
GLOBIGNORE=*
hour="*"
echo hour
fi
In general (all test []) are missing a ; after it:
if [ $hour -eq 0 ]; then
The echo hour will not print the value of var hour but the word hour. Change to echo "$hour" (yes, quoted). Also, there is no need to set the variable GLOBIGNORE to * if vars are properly quoted.
The vars here are not quoted, that is a reason for it to fail (or to need GLOBIGNORE):
echo $minute $hour $day $month $weekday
Change to:
echo "$minute $hour $day $month $weekday"
The redirection on that same line is a plain >, that will empty the file.
If you want to append to the files, do as this:
echo "$minute $hour $day $month $weekday" "$(date >> ~/testcron.log)" >>testcron.txt
In that line there is an unneeded additional fi
This script may be of help:
get(){
read -p "$1" "$2"
if [ "$((${!2}))" -eq 0 ]; then
eval "$2"="*"
echo "${!2}"
fi
}
read -p "Choice?:" choice
if [ "$choice" -eq "1" ]; then
get "Enter the MINUTE" minute
get "Enter the Hour" hour
get "Enter the Day" day
get "Enter the Month" month
get "Enter the weekday" weekday
date >> ~/testcron.log
echo "$minute $hour $day $month $weekday" >> testcron.txt
elif [ "$choice" -eq "2" ]; then
echo "Enter the Source and Destination Locations"
fi
You are missing a semi-colon:
if [ $choice -eq "1" ]; then
or
if [ $choice -eq "1" ]
then
A semi-colon or a newline is required because the command is actually [ and has to be terminated after the ], which is just the last argument given to [.
That is the old test (or [) syntax, you could also use:
if (( choice == 1 ))
then
Hello I am trying to make a program in Ubuntu shell and the program crashes after I input the variables. The code is as follows: http://pastebin.com/Chu4DPgF
#!/bin/bash
echo -n "Enter assignment mark:"
read assign
echo -n "Enter Test 1 mark:"
read test1
echo -n "Enter Test 2 mark:"
read test2
echo -n "Enter Final Exam mark:"
read final
total=$(($assign + $test1 + $test2 + $final))
if [[ $total -ge 90 && $total -le 100 ]]; then
echo "Your grade is A+"
elif [[ $total -ge 85 && $total -le 89 ]]; then
echo "Your grade is A"
elif [[ $total -ge 80 && $total -le 84 ]]; then
echo "Your grade is A-";
elif [[ $total -ge 77 && $total -le 79 ]]; then
echo "Your grade is B+"
elif [[ $total -ge 73 && $total -le 76 ]]; then
echo "Your grade is B"
elif [[ $total -ge 70 && $total -le 72 ]]; then
echo "Your grade is B-"
elif [[ $total -ge 67 && $total -le 69 ]]; then
echo "Your grade is C+"
elif [[ $total -ge 63 && $total -le 66 ]]; then
echo "Your grade is C"
elif [[ $total -ge 60 && $total -le 62 ]]; then
echo "Your grade is C-"
elif [[ $total -ge 57 && $total -le 59 ]]; then
echo "Your grade is D+"
elif [[ $total -ge 53 && $total -le 56 ]]; then
echo "Your grade is D"
elif [[ $total -ge 50 && $total -le 52 ]]; then
echo "Your grade is D-"
elif [[ $total -ge 0 && $total -le 49 ]]; then
echo "Your grade is F"
else
echo "?"
fi
I have no idea what is wrong with the code. I'm sure there is a fundamental problem with it. Thanks in advance.
change line 15 to
((total = assign + test1 + test2 + final ))
and all the following lines of this format to:
if [[ $total -ge 90 && $total -le 100 ]]; then
echo "Your grade is A+"
to
if [ $total -ge 90 ] && [ $total -le 100 ]; then
echo "Your grade is A+"
and it should work.
Be exact with the white-spaces