Ubuntu Shell Scripting Issue - shell

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

Related

Grade Calculator Script Linux assistance

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.)

Values of an array not comparing to numbers correctly

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

How can I readably/tersely/correctly check in whether a value is in one of two ranges?

I need help writing a better code for the following logic:
if [[ "$CONDITION1" == "BAD" && "$PERCENT1" -ge 10 && "$PERCENT1" -le 30 ]] || [[ "$CONDITION1" == "GOOD" && "$PERCENT1" -ge 30 && "$PERCENT1" -le 60 ]] || [[ "$CONDITION2" == "BAD" && "$PERCENT2" -ge 10 && "$PERCENT2" -le 30 ]] || [[ "$CONDITION2" == "GOOD" && "$PERCENT2" -ge 30 && "$PERCENT2" -le 60 ]];
then
echo "RESULT 1"
elif [[ "$CONDITION1" == "BAD" && "$PERCENT1" -gt 30 ]] || [[ "$CONDITION1" == "GOOD" && "$PERCENT1" -gt 60 && "$PERCENT1" -le 100 ]] || [[ "$CONDITION2" == "BAD" && "$PERCENT2" -gt 30 ]] || [[ "$CONDITION2" == "GOOD" && "$PERCENT2" -gt 60 && "$PERCENT2" -le 100 ]];
then
echo "RESULT 2"
else
echo "RESULT 3"
fi
This is the basis for the conditions:
RESULT 1:
PERCENT1 is 10-30% if CONDITION1=BAD
OR PERCENT1 is 30-60% if CONDITION1=GOOD
OR PERCENT2 is 10-30% if CONDITION2=BAD
OR PERCENT2 is 30-60% if CONDITION2=GOOD
RESULT 2:
PERCENT1>30% if CONDITION1=BAD
OR PERCENT1 is 60-100% if CONDITION1=GOOD
OR PERCENT2>30% if CONDITION2=BAD
OR PERCENT2 is 60-100% if CONDITION2=GOOD
Result 2 overrides Result 1. For example:
PERCENT1 is 10-30% and CONDITION1=BAD AND
PERCENT2>30% and CONDITION2=BAD will result in RESULT 1.
You can't clean this up to much, but it can be made better. Since you require result 2 overriding result one, you need two if statements, with the override running second. Technically, you could do it with an elif, with the override being the if, and the inferior one being the elif, but this logic is more difficult to read, and when the complexity of your requirements would produce very long conditions.
RESULT=3 # default to result 3
if [[ $PERCENT1 -ge 10 && $PERCENT1 -le 30 && $CONDITION1 = "BAD" ]]; then
RESULT=1
elif [[ $PERCENT1 -ge 30 && $PERCENT1 -le 60 && $CONDITION1 = "GOOD" ]]; then
RESULT=1
elif [[ $PERCENT2 -ge 10 && $PERCENT2 -le 30 && $CONDITION1 = "BAD" ]]; then
RESULT=1
elif [[ $PERCENT2 -ge 30 && $PERCENT2 -le 60 && $CONDITION2 = "GOOD" ]]; then
RESULT=1
fi
# RESULT 2 should override result one
if [[ $PERCENT1 -gt 30 && $CONDITION1 = "BAD" ]]; then
RESULT=2
elif [[ $PERCENT1 -ge 60 && $PERCENT1 -le 100 && $CONDITION1 = "GOOD" ]]; then
RESULT=2
elif [[ $PERCENT2 -gt 30 && $CONDITION1 = "BAD" ]]; then
RESULT=2
elif [[ $PERCENT2 -ge 60 && $PERCENT2 -le 100 && $CONDITION1 = "GOOD" ]]; then
RESULT=2
fi
echo "RESULT $RESULT" # output our result
Since it doesn't matter how many times RESULT 1 or RESULT 2 are hit, then the elifs work fine. Note that I changed your -ge 30 to -gt 30 since you used > 30 and not >= 30 in your explanations for the conditions. Not sure which one was a typo.

bash elif does not work as I expected

Here is my script:
age=119
if [[$age -gt 99 ]]; then
age_3digits=$age
elif [[$age -gt 9]]; then
age_3digits=0$age
else
age_3digits=00$age
fi
z_grid=${age_3digits}Ma.grd
echo $z_grip
output: 00119Ma.grd
how come?? I am new to bash, thanks so much
You need a space after [[ and before ]]. Change to:
if [[ $age -gt 99 ]]; then
age_3digits=$age
elif [[ $age -gt 9 ]]; then
age_3digits=0$age
else
age_3digits=00$age
fi
It's also better to use arithmetic expressions because it makes your code more readable, like this:
if (( age > 99 )); then
age_3digits=$age
elif (( age > 9 )); then
age_3digits=0$age
else
age_3digits=00$age
fi

Linux Script: Returning a range when given list

So I am still learning shell scripting and am trying to figure out how to return a string of numbers. My code is as follows:
#!/bin/bash
read -p "Enter NUM1 " NUM1
read -p "Enter NUM2 " NUM2
if [ $NUM1 -gt $NUM2 ]; then $NUM1=g1 && $NUM2=g2
elif [ $NUM2 -gt $NUM1 ]; then $NUM2=g1 && $NUM1=g2; fi
for VALUE in $#; do
if [ $VALUE -lt $g1 ] && [ $VALUE -gt $g2 ]; then COUNT=$((COUNT+1)); fi
done
echo $VALUE happened $COUNT times
Essentially I would pass a list of numbers and want the number of matches between g1 and g2 returned as well as the the matches themselves. Any help is appreciated.
The problem is that you inverted the order on the g1 and g2 assignment!
Here's your script working:
#!/bin/bash
read -p "Enter NUM1 " NUM1
read -p "Enter NUM2 " NUM2
if [ $NUM1 -gt $NUM2 ]; then g1=$NUM1 && g2=$NUM2
elif [ $NUM2 -gt $NUM1 ]; then g1=$NUM2 && g2=$NUM1; fi
for VALUE in $#; do
if [ $VALUE -lt $g1 ] && [ $VALUE -gt $g2 ]; then COUNT=$((COUNT+1)); fi
done
echo $VALUE happened $COUNT times

Resources