Updating sub-menus variables - bash

I have a problem with this bash script:
#!/bin/bash
G=100
echo $G
main_menu()
{
while :
do
clear
echo "Select from menu"
echo "[1] Press 1 to show savings"
echo "[2] Press 2 to withdraw savings"
echo "[3] Press 3 to exit"
echo "Enter your menu choice [1-3]: \c "
read -r m_menu
case "$m_menu" in
1) option_1;;
2) option_2;;
3) exit 0;;
*) echo "\nERROR: Please select a valid menu choice";
echo "Press ENTER To Continue..." ; read ;;
esac
done
}
option_1()
{
clear
echo "Your balance is $G"
echo "\nPress ENTER to return to menu..."
read
return
}
option_2()
{
clear
echo "Withdraw savings"
read -rp "Enter amount to withdraw: " num
if [ $num -le $G ]; then
answer=$(echo $(( G - num )))
echo "Your new balance is: $answer"
echo "$answer" | tee "$G"
elif [ $num -gt $G ]; then
echo "No: not eough money in your balance"
fi
read
return
}
main_menu
The problem is the following: how do I make sure that once I withdraw savings, my saving count will be updated? Because if I withdraw $90, obviously when I return to the balance it should be $10 and yet this doesn't work for me (it still says saving balance is $100)
What can I do?
Thank you (sorry for my poor English)

You have to update G in your code.
if [ $num -le $G ]; then
G=$(( G - num ))
echo "Your new balance is: $G"

Related

Return to previous commands in bash script?

I'm trying to implement a prev option in my bash script to go back to the previous "menu", as well as a way for the script to ask for user input again if no variable is set for $name.
Heres my bash script:
#!/bin/bash
#Menu() {
for (( ; ; ))
do
beginORload=
echo "Choose option:"
echo "1 - Begin"
echo "2 - Load"
read -p "?" beginORload
#}
#Begin() {
if [ "$beginORload" -eq "1" ]
then
clear
for (( ; ; ))
do
echo "Beginning. What is your name?"
read -p "?" name
#If "prev" specified, go back to #Menu()
if [ "$name" -eq "prev" ]
then
Menu
fi
#If nothing specified, return to name input
if [ -z ${name+x} ]
then
Begin
else
break
fi
echo "Hi $name !"
done
fi
done
In batch, I could simply do:
:menu
echo Choose option:
echo 1 - Begin
echo 2 - Load
[...]
:begin
[...]
if "%name%==prev" goto menu
if "%name%==" goto begin
the issue is I keep running into errors all over the place, and I can't figure out what to type to get it to work
im running Yosemite btw. Thankyou
Something like this is close to what you expect:
while [[ $answer -ne '3' ]];do
echo "Choose option:"
echo "1 - Begin"
echo "2 - Load"
echo "3 - Exit"
read -p "Enter Answer [1-2-3]:" answer
case "$answer" in
1) while [[ "$nm" == '' ]];do read -p "What is your Name:" nm;done # Keep asking for a name if the name is empty == ''
if [[ $nm == "prev" ]];then nm=""; else echo "Hello $nm" && break; fi # break command breaks the while wrapper loop
;;
2) echo 'Load' ;;
3) echo 'exiting...' ;; # Number 3 causes while to quit.
*) echo "invalid selection - try again";; # Selection out of 1-2-3 , menu reloaded
esac # case closing
done # while closing
echo "Bye Bye!"
As a general idea you can wrap up your case selection in a while loop which will break under certain circumstances (i.e If Option 3 is selected or if a valid name is given (not blank - not prev)
PS1: In bash you compare integers with -eq , -ne, etc but you compare strings with == or !=
PS2: Check the above code online here

Infinite loop on yes/no ksh

I have an annoying issue that seems to cause and infinite loop and I can't work out why. If I call the following function, it keeps repeating the yes/no options infinitely down the screen until I crash out.
AuditUpload() {
clear
echo "Audit report generated successfully"
echo " "
echo "Do you wish to upload qhub_audit.csv? (1 = Yes/2 = No):"
sleep 1
select yn in "Yes" "No"; do
case $yn in
Yes ) AuditUploader; Auditvi; exit;;
No ) echo "Upload cancelled"; Auditvi; exit;;
esac
done
}
I put the sleep in to see if it would remedy the issue but it still does the same. This issue seems to be very intermittent and doesn't happen every time. This script is written in korn shell (ksh).
AuditUploader function:
AuditUploader() {
echo "Uploading qhub_audit.csv to $HOST..."
curl -v -T qhub_audit.csv -# ftp://xxxxxxxx:xxxxxxxxx#xxxxxxxxxxxxx.com/
if [ "$?" -ne "0" ]
then
echo "ERROR: Cannot upload qhubload.csv"
exit
else
clear
echo "qhub_audit.csv has been put on $HOST successfully"
tput cup 5 5
echo "Copy and paste this link into internet explorer to download:"
tput cup 7 5
echo "ftp://xxxxxxxx:xxxxxxxxx#xxxxxxxxxxxxx.com/qhub_audit.csv"
read LINK
fi
}
Auditvi function:
Auditvi() {
clear
echo "Do you wish to view qhub_audit.csv? (1 = Yes/2 = No):"
sleep 1
select yn in "Yes" "No"; do
case $yn in
Yes ) vi qhub_audit.csv; exit;;
No ) exit;;
esac
done
}
After a bit of playing around it looks like it was looping whenever the 'curl' command returned a specific error which stopped the kill $$ from working properly. I replaced kill $$ with exit 1 and amended the other functions accordingly. I also put in a contingency to use kermit in case the FTP failed. Anyway, this is what my code looks like now:
#########################################
# Upload quotehub audit report function #
#########################################
AuditUploader() {
echo "Uploading qhub_audit.csv to $HOST..."
curl -v -T qhub_audit.csv -# ftp://$USER:$PASSWD#$HOST/ -m 10
if [ "$?" -ne "0" ]
then
echo "ERROR: Cannot upload qhubload.csv via FTP"
if [ ${term} = "tty1A" ]
then
echo "Attempting to download to modems server..."
wermit -s qhub_audit.csv
if [ $? -ne 0 ]
then
echo "Cannot upload to modems either!"
echo "This file will have to be downloaded manually"
exit 1
else
clear
echo "qhub_audit.csv has been put on modems server successfully"
tput cup 5 5
echo "Copy and paste this link into START -> RUN to download:"
tput cup 7 5
echo "\\\\\\xxxxxxxx\download\general\qhub_audit.csv"
read LINK
fi
else
echo "Upload failed!"
exit 1
fi
else
clear
echo "qhub_audit.csv has been put on $HOST successfully"
tput cup 5 5
echo "Copy and paste this link into internet explorer to download:"
tput cup 7 5
echo "ftp://$USER:$PASSWD#$HOST/qhub_audit.csv"
read LINK
fi
}
#######################################################
# Function to prompt user to upload qhub audit report #
#######################################################
AuditUpload() {
clear
echo "Audit report generated successfully"
echo ""
echo "Do you wish to upload qhub_audit.csv? (y/n):"
read REPLY
case "$REPLY" in
Y) AuditUploader; Auditvi; exit;;
y) AuditUploader; Auditvi; exit;;
N) Auditvi; exit;;
n) Auditvi; exit;;
*) echo "invalid option";;
esac
}
######################################
# Function to view qhub audit report #
######################################
Auditvi() {
if [ "$?" -ne "0" ]
then
exit 1
else
clear
echo "Do you wish to view qhub_audit.csv? (y/n):"
read REPLY
case "$REPLY" in
Y) vi qhub_audit.csv; exit;;
y) vi qhub_audit.csv; exit;;
N) exit;;
n) exit;;
*) echo "invalid option"; Pause; Auditvi;;
esac
fi
}
Thanks again guys for all your help.

Error getting an output from a users selection bash shell in Linux

He friends. I am creating a script file to be able to read users input and display an output based on the question i am asking. When i run the choices separately they work fine but cant figure out why they will not display when i put pieces together.
#!/bin/bash
while test $loop = "y"
do
echo "$CLEAR"
clear
tput cup 5 12 ; echo "L- List all wines by name in alphabetical order."
tput cup 6 12 ; echo "C- Count all wines in each type and list all 5 types with their count."
tput cup 10 12; echo "E- Exit the program."
read choice || continue
case $choice in
[Ll]) file="/home/students/domie/wine.txt"; sort -t ":" -k2 $file;; #no output here
[Cc]) ./count ;; #look below for count script
[Ee]) clear; exit ;; #this works when script runs
*) tput cup 14 4; echo "Invalid Code,Press Enter and Try Again"; read choice ;;
esac
done
and the count script:
$vi count
while IFS=":" read -ra line; do
if (( ${line[2]} == 2 )); then
IFS=":" && echo "${line[*]}"
(( count++ ))
fi
done < /home/students/domie/wine.txt
echo "Count = $count"
EDITED:
wine.txt
Try this:
#!/bin /bash
file="wine.txt"
count() {
# Replace below with your counting logic ..
while IFS=":" read -ra line; do
if (( ${line[2]} == 2 )); then
IFS=":" && echo "${line[*]}"
(( count++ ))
fi
done < "$file"
echo "Count = $count"
}
pause() {
read -p "$*"
}
while :; do
clear
echo "L- List all wines by name in alphabetical order."
echo "C- Count all wines in each type and list all 5 types with their count."
echo "E- Exit the program."
read -p "Enter Choice: " choice || continue
case $choice in
[Ll]) sort -t ":" -k2,2 "$file" ; pause 'Press [Enter] key to continue...';;
[Cc]) count ; pause 'Press [Enter] key to continue...';;
[Ee]) exit ;;
*) pause "Invalid Code, Press Enter and Try Again" ;;
esac
done

First Bash script problems with case statement

Just what it says. I'm trying to write a simple bash script from a question in a book. I'm trying to use the case statement, and for all I can tell I am using it correctly. However I keep getting "syntax error near unexpected token '$'in\r' case $i in.
No idea why. I'm also sure there are other problems in my code since this is my first script. The case statement is on line 10. Feel free to correct anything else, the end program will be building a grade data file for student grades, using a simple awk script to compute the average of the grades, and putting everything in the output file.
function getStudentData () {
i=0
while [ $i<5 ]
do
case $i in
[0]) echo -n "Enter student name\n"
read name
;;
[1]) echo -n "Enter Quiz grade\n"
read quiz
checkLimits $quiz
;;
[2]) echo -n "Enter homework grade\n"
read hw
checkLimits $hw
;;
[3]) echo -n "Enter midterm grade\n"
read midterm
checkLimits $midterm
;;
[4]) echo -n "Enter Final grade \n"
read final
checkLimits $final
;;
esac
done
}
function checkLimits ($grade) {
if [ grade <= 100 || grade >= 0 ]; then
$i--
fi
}
if [ $# -lt 2 ]; then
echo "Incorrect number of arguments"
exit 1
fi
#Check awk existance
if [ ! -e $2 ]; then
echo "Error, .awk file does not exist"
exit 1
fi
#flag for data file existing, and awk file
flag=0
#Check for data file existing
if [ ! -e $1 ];then
flag=0
else
flag=1
fi
ans="yes"
while [ $ans == "yes" || $ans == "y" ]
do
echo "Do you want to enter a student record?"
read ans
if [ $ans == "y" || $ans == "yes" ];then
getStudentData
else
echo "we done"
exit 1
fi
done
If you write it as a loop, then you should probably write:
function getStudentData () {
i=0
while [[ $i < 5 ]]
do
case $i in
0) echo -n "Enter student name: "
read name
;;
1) echo -n "Enter Quiz grade: "
read quiz
checkLimits $quiz
;;
2) echo -n "Enter homework grade: "
read hw
checkLimits $hw
;;
3) echo -n "Enter midterm grade: "
read midterm
checkLimits $midterm
;;
4) echo -n "Enter Final grade: "
read final
checkLimits $final
;;
esac
done
}
function checkLimits() {
if [[ $1 -gt 100 || $1 -lt 0 ]]
then ((i--))
fi
}
This fixes a number of problems:
The test condition in the while loop.
The non-obvious use of echo -n to suppress a newline plus the \n to add a newline.
The indentation.
The syntax of the checkLimits() function.
The syntax of the condition in the checkLimits() function.
Uninverts the inverted logic of the condition in the checkLimits() function.
Actually decrements the variable i.
It does not fix the reliance on the global variable $i, which is pretty ugly.
The purpose of the loop must be to go back if there's an error and get the data reentered. That's a clever idea. Unfortunately, you never increment $i, so it doesn't really work.
Here is some working code:
function getStudentData () {
for ((i = 0; i < 5; i++))
do
case $i in
0) echo -n "Enter student name: "
read name
;;
1) echo -n "Enter Quiz grade: "
read quiz
checkLimits $quiz
;;
2) echo -n "Enter homework grade: "
read hw
checkLimits $hw
;;
3) echo -n "Enter midterm grade: "
read midterm
checkLimits $midterm
;;
4) echo -n "Enter Final grade: "
read final
checkLimits $final
;;
esac
done
}
function checkLimits() {
if [[ $1 -gt 100 || $1 -lt 0 ]]
then ((i--))
fi
}
getStudentData
echo "Name = $name"
echo "Quiz = $quiz"
echo "Homework = $hw"
echo "Midterm = $midterm"
echo "Final = $final"
The output from a sample run:
Enter student name: Eileen
Enter Quiz grade: 92
Enter homework grade: 94
Enter midterm grade: 95
Enter Final grade: 97
Name = Eileen
Quiz = 92
Homework = 94
Midterm = 95
Final = 97

Creating a calculator script

I am trying to make a calculator with a bash script.
The user enters a number, chooses whether they wish to add, subtract, multiply or divide. Then the user enters a second number and is able to choose whether to do the sum, or add, subtract, multiply or divide again on a loop.
I cannot rack my head around this right now
echo Please enter a number
read number
echo What operation would you like to perform: 1: Add, 2: Subtract, 3: Multiple, 4: Divide
read operation
case $operation in
1) math='+';;
2) math='-';;
3) math='*';;
4) math='/';;
*) math='not an option, please select again';;
esac
echo "$number $math"
echo Please enter a number
read number2
echo What operation would you like to perform: 1: Add, 2: Subtract, 3: Multiple, 4: Divide, 5: Equals
read operation2
case $operation2 in
1)math2='Add';;
2)math2='Subtract';;
3)math2='Multiply';;
4)math2='Divide';;
5)math2='Equals';;
*)math2='not an option, please select again';;
esac
echo You have selected $math2
exit 0
This is what I have done so far, but can anyone help me work out how to loop back on the calculator?
The lesser-known shell builtin command select is handy for this kind of menu-driven program:
#!/bin/bash
while true; do
read -p "what's the first number? " n1
read -p "what's the second number? " n2
PS3="what's the operation? "
select ans in add subtract multiply divide; do
case $ans in
add) op='+' ; break ;;
subtract) op='-' ; break ;;
multiply) op='*' ; break ;;
divide) op='/' ; break ;;
*) echo "invalid response" ;;
esac
done
ans=$(echo "$n1 $op $n2" | bc -l)
printf "%s %s %s = %s\n\n" "$n1" "$op" "$n2" "$ans"
done
Sample output
what's the first number? 5
what's the second number? 4
1) add
2) subtract
3) multiply
4) divide
what's the operation? /
invalid response
what's the operation? 4
5 / 4 = 1.25000000000000000000
If I was going to get fancy with bash v4 features and DRY:
#!/bin/bash
PS3="what's the operation? "
declare -A op=([add]='+' [subtract]='-' [multiply]='*' [divide]='/')
while true; do
read -p "what's the first number? " n1
read -p "what's the second number? " n2
select ans in "${!op[#]}"; do
for key in "${!op[#]}"; do
[[ $REPLY == $key ]] && ans=$REPLY
[[ $ans == $key ]] && break 2
done
echo "invalid response"
done
formula="$n1 ${op[$ans]} $n2"
printf "%s = %s\n\n" "$formula" "$(bc -l <<< "$formula")"
done
Wrapping Code in a Loop
If you just want to wrap your code in a Bash looping construct, and are willing to hit CTRL-C to terminate the loop rather than do something more fancy, then you can wrap your code in a while-loop. For example:
while true; do
: # Your code goes here, inside the loop.
done
Just make sure to move your unconditional exit statement out of the body of the loop. Otherwise, the loop will terminate whenever it reaches that line.
For your ~/.bashrc:
alias bc="BC_ENV_ARGS=<(echo "scale=2") \bc"
Just use bc, with that alias it automatically works with two decimals instead of integers.
!/bin/bash
PS3="what's the operation? "
declare -A op=([add]='+' [subtract]='-' [multiply]='*' [divide]='/')
while true; do
read -p "what's the first number? " n1
read -p "what's the second number? " n2
select ans in "${!op[#]}"; do
for key in "${!op[#]}"; do
[[ $REPLY == $key ]] && ans=$REPLY
[[ $ans == $key ]] && break 2
done
echo "invalid response"
done
formula="$n1 ${op[$ans]} $n2"
printf "%s = %s\n\n" "$formula" "$(bc -l <<< "$formula")"
done
Please use the following script.
clear
sum=0
i="y"
echo " Enter one no."
read n1
echo "Enter second no."
read n2
while [ $i = "y" ]
do
echo "1.Addition"
echo "2.Subtraction"
echo "3.Multiplication"
echo "4.Division"
echo "Enter your choice"
read ch
case $ch in
1)sum=`expr $n1 + $n2`
echo "Sum ="$sum;;
2)sum=`expr $n1 - $n2`
echo "Sub = "$sum;;
3)sum=`expr $n1 \* $n2`
echo "Mul = "$sum;;
4)sum=`expr $n1 / $n2`
echo "Div = "$sum;;
*)echo "Invalid choice";;
esac
echo "Do u want to continue ?"
read i
if [ $i != "y" ]
then
exit
fi
done
#calculator
while (true) # while loop 1
do
echo "enter first no"
read fno
if [ $fno -eq $fno 2>/dev/null ]; # if cond 1 -> checking integer or not
then
c=1
else
echo "please enter an integer"
c=0
fi # end of if 1
if [ $c -eq 1 ]; #if 2
then
break
fi # end of if 2
done # end of whie 1
while(true) #while loop 2
do
echo "enter second no"
read sno
if [ $sno -eq $sno >/dev/null 2>&1 ] # if cond 3 -> checking integer or not
then
c=1
else
echo "please enter an integer"
c=0
fi # end of if 3
if [ $c -eq 1 ] # if cond 4
then
break
fi # end of if 4
done #2
while(true) # while loop 3
do
printf "enter the operation (add,div,mul,sub) of $fno and $sno\n"
read op
count=0
##addition
if [ $op = add ] #if cond 5
then
echo "$fno+$sno is `expr $fno + $sno`"
#multiplication
elif [ $op = mul ];
then
echo "$fno*$sno is `expr $fno \* $sno`"
#substraction
elif [ $op = sub ]
then
while(true) #while loop 3.1
do
printf "what do you want to do??? \n 1. $fno-$sno \n 2. $sno-$fno"
printf "\n press the option you want to perform?(1 or 2)\n"
read opt
if [ $opt = 1 ] #if cond 5.1
then
echo "$fno-$sno is `expr $fno - $sno`"
break
elif [ $opt = 2 ]
then
echo " $sno-$fno is `expr $sno - $fno`"
break
else "please enter valid options to proceed(1 or 2)";
clear
fi #end of if 5.1
done # end of 3.1
#division
elif [ $op = div ]
then
while(true) # whilw loop 3.2
do
printf "what do you want to do??? \n 1. $fno/$sno \n 2. $sno/$fno"
printf "\n press the option you want to perform?(1 or 2)\n"
read opt
if [ $opt = 1 ] #if cond 5.2
then
echo "$fno divided by $sno is `expr $fno / $sno`"
break
elif [ $opt = 2 ]
then
echo " $sno divided by $fno is `expr $sno / $fno`"
break
else
clear
fi #end of if 5.2
done # end of 3.2
else
echo "valid option please!!!"
count=1
fi # end of if 5
if [ $count -eq 0 ] #if cond 6
then
echo "Do you want to do more ops"
echo "(y/n)"
read ans
clear
if [ $ans = n ] # if 6.1
then
break
fi # end of if 6.1
fi #end of if 6
done #end of while 3

Resources