I have a script that I cannot get to work, despite my best efforts. I really hope someone can help. Very new to programming, so still learning the ropes. I'm building an interactive shell script that requires the user to put in an operand, and then another operand, to produce the maths table for the 2nd operand. e.g. I select "+" & number "2" (from a range of 15), and it prints out the table for "2+1=3, 2+2 =4" etc. to a range of 10. Here is my current script;
#!/bin/sh
echo "Please select the function you wish to perform from the following list"
echo " Multiplication = *"
echo " Addition = +"
echo " Subtraction = -"
echo " Division = /"
echo " Exponent = ^"
read s
echo "Please select a number between 1 and 15"
read n
i = 1
while [$i ‽ le 10]
do
if [$s = "*"]
then
echo "$n x $i = $((n*i))";
elif [ $s = "+"]
echo "$n + $i = $((n+i))";
elif [$s = "-"]
echo "$n - $i = $((n-i))";
elif [$s = "/"]
echo "$n / $i = $((n/i))";
elif [$s = "^"]
echo "$n ^ $i = $((n^i))";
fi
i = $((i+1))
done
I know my while loop is incorrect, so I would really appreciate any help here! Thank you!
After some modifications :
#!/bin/sh
echo "Please select the function you wish to perform from the following list"
echo " Multiplication = *"
echo " Addition = +"
echo " Subtraction = -"
echo " Division = /"
echo " Exponent = ^"
read s
echo "Please select a number between 1 and 15"
read n
i=1
while [ "$i" -le 10 ]
do
if [ "$s" = "*" ]; then
echo "$n x $i = $((n*i))";
elif [ "$s" = "+" ]; then
echo "$n + $i = $((n+i))";
elif [ "$s" = "-" ]; then
echo "$n - $i = $((n-i))";
elif [ "$s" = "/" ]; then
echo "$n / $i = $((n/i))";
elif [ "$s" = "^" ]; then
echo "$n ^ $i = $((n^i))";
fi
i=$((i+1))
done
Related
I am trying to make a simple menu-driven calculator script. I am trying to make it such that after selecting A (add) or B (subtract) from the menu, it'll call the function and display the corresponding message when:
The parameters entered when function called is greater than 3
No parameters are entered when the function is called
The operator entered when the function is called is neither "+" or "-"
Right now it is doing the parameter check when I call the script ./mycalc.sh
executing the script
Am not sure how to make it check parameters after the function is called?
#!/bin/bash
display() {
echo "Calculator Menu"
echo "Please select an option between add, subtract or exit"
echo "A. Add"
echo "B. Subtract"
echo "C. Exit"
}
#initialize choice n
choice=n
if [[ $# -ne 3 ]]
then echo " You have not entered 3 parameters"
exit 1
fi
if [ $# -eq 0 ]
then
echo " You have not entered any parameters, please input 3. "
fi
if [[ $2 != [+-] ]]
then
echo " Please enter an add or subtract operator."
exit 1
fi
add() {
echo " The sum of $one + $three equals $(( $one $op $three ))"
}
subtract () {
echo " The difference of $one - $three equals $(( $one $op $three )) "
}
while [ $choice != 'C' ]
do display
read choice
if [ $choice = 'A' ]
then
read -p "Please enter two operands and the operator '+': " one op three
add $one $op $three
elif [ $choice = 'B' ]
then
read -p " Please enter two operands and the operator '-': " one op three
subtract $one $op $three
elif [ $choice = 'C' ]
then
echo "Thank you for using this program. The program will now exit."
fi
done
sleep 3
exit 0
if [ $# > 3 ]
then
echo " You need to input 3 parameters. "
fi
Within [...], the > is simply redirection. You'll find an empty file named 3 in your current directory.
Since this is an error condition for your script, you'll want to exit:
if [[ $# -ne 3 ]]; then
echo "usage: $0 operand1 operator operand2" >&2
exit 1
fi
And to test the operator, there are many ways.
case, but it's a bit verbose
case $2 in
'+'|'-') : ;;
*) echo "Operator must be + or -" >&2
exit 1
;;
esac
Within [[...]] the == and != operators are pattern matching operators
if [[ $2 != [+-] ]]; then
echo "Operator must be + or -" >&2
exit 1
fi
I am trying to make a simple calculator. I am sure if you even just glanced at this code you will see what I am trying to do.
Enter a number, then choose an operand, then vim should print out a table up to 15 with your number and operand...
Maybe this method is silly, trying to nest a load of loops in nested if statements. But I am new to bash.
The error is 'Unexpected token near else' line 24 but I feel there is a fundamental issue with the nests I do not understand.
Here is current code.
#!/bin/bash
choice=6
read -p "Enter a number bruv" num
#choose operand.
echo "Now choose an operand comrade"
#choices
echo "1. *"
echo "2. +"
echo "3. -"
echo "4. /"
echo "5. ^"
echo -n "Please choose [1,2,3,4,5]"
while [ $choice -eq 6 ]; do
read choice
if [ $choice -eq 1 ] ; then
for((i=0;i<=15;i++))
do
echo -n "$i * $num = $[ $i * $num ] "
echo " "
else
if [ $choice -eq 2 ] ; then
for((i=0;i<=15;i++))
do
echo -n "$i + $num = $[ $i + $num ] "
echo " "
else
if [ $choice -eq 3 ] ; then
for((i=0;i<=15;i++))
do
echo -n "$i - $num = $[ $i - $num ] "
echo " "
else
if [ $choice -eq 4 ] ; then
for((i=0;i<=15;i++))
do
echo -n "$i / $num = $[ $i / $num ] "
echo " "
else
if [ $choice -eq 5 ] ; then
for((i=0;i<=15;i++))
do
echo -n "$i ^$num = $[ $i ^$num ] "
echo " "
else echo "Please choose between 1 and 5!!!"
echo "1. *"
echo "2. +"
echo "3. -"
echo "4. /"
echo "5. ^"
echo -n "Please choose [1,2,3,4,5]"
fi
fi
fi
fi
fi
done
Would it be better to implement this?
# !/bin/bash
# Take user Input
echo "Enter number : "
read a
# Input type of operation
echo "Enter Choice :"
echo "1. Addition"
echo "2. Subtraction"
echo "3. Multiplication"
echo "4. Division"
echo "5. Power"
read ch
# Switch Case to perform
# calulator operations
case $ch in
1)res=`for((i=0;i<=15;i++))
do
echo -n "$i - $num = $[ $i - $num ] "
echo " "`
;;
2)res=`for((i=0;i<=15;i++))
do
echo -n "$i - $num = $[ $i - $num ] "
echo " "`
;;
3)res=`for((i=0;i<=15;i++))
do
echo -n "$i - $num = $[ $i - $num ] "
echo " "`
;;
4)res=`for((i=0;i<=15;i++))
do
echo -n "$i - $num = $[ $i - $num ] "
echo " "c`
;;
esac
echo "Result : $res" ```
Here is a solution, using a function:
#! /bin/bash
ITER_MAX=15
show_values() # n op
{
local n=$1 op=$2
for ((i=0; i<=ITER_MAX; i++)); do
((i>0)) && echo -n " ; "
echo -n "$i $op $n = $((i $op n))"
done
echo
}
# Take user Input
read -p "Enter number : " a
# Input type of operation
echo "Enter Choice (Ctrl+C to stop):"
PS3=">> "
select ch in Addition Subtraction Multiplication Division Power ; do
case "$ch" in
Add*) op="+" ;;
Sub*) op="-" ;;
Mul*) op="*" ;;
Div*) op="/" ;;
Pow*) op="**" ;;
*) echo "Bad choice, abort" >&2 ; break ;;
esac
show_values "$a" "$op"
done
Some explanations:
(( )) is arithmetic evaluation and $(( )) is arithmetic expansion
((i>0)) && echo -n " ; " is equivalent to if ((i>0)); then echo -n " ; " ; fi
read -p "Enter number : " a is equivalent to echo -n "Enter number : " ; read a
about select, see help select in your bash terminal.
Use https://www.shellcheck.net/
Line 20:
for((i=0;i<=15;i++))
^-- SC1009: The mentioned syntax error was in this for loop.
^-- SC1073: Couldn't parse this arithmetic for condition. Fix to allow more checks.
Line 21:
do
^-- SC1061: Couldn't find 'done' for this 'do'.
Line 24:
else
^-- SC1062: Expected 'done' matching previously mentioned 'do'.
^-- SC1072: Unexpected keyword/token. Fix any mentioned problems and try again.
An alternate take:
read -p "Enter a number and an operator: " -a a
for n in {1..15}; do printf "%+10s\n" $((${a[#]} $n)); done
-p tells read to supply a prompt. -a reads into an array (named a here).
{1..15} is built-in bash sequence syntax.
%+10s tells printf to space-pad/right justify out to 10 characters.
${a[#]} is replaced with all the elements of the array - the number and then operator.
$(( ... )) does arithmetic processing and replaces itself with the result (as a string).
So if you enter "10 *" then $((${a[#]} $n)) processes 10 * 1 the first time, so printf "%+10s\n" $((${a[#]} $n)) outputs " 10" with a trailing newline character. Then the loop replaces the 1 with the next number on each iteration, up to 15. This also allows other operators, such as % for modulus, but will crash if something invalid is given.
If you want error checking -
while [[ ! "${a[*]}" =~ ^[0-9][0-9]*\ ([*/+-]|\*\*)$ ]]
do read -p "Enter a, integer and an operator (one of: + - * / **) " -a a
done
for n in {1..15}; do printf "%+10s\n" $((${a[#]} $n)); done
If you want floating point math, try bc:
while [[ ! "${a[*]}" =~ ^[0-9]+.?[0-9]*\ ([*/+-]|\*\*)$ ]]
do read -p "Enter a, integer and an operator (one of: + - * / **) " -a a
done
for n in {1..15}; do printf "%+15s\n" $(bc -l <<< "scale=3;${a[#]} $n"); done
Personally, I'd put the inputs on the command line. Less futzy, though it might require quoting the * operator, depending on how you run it and what's in the directory.
#!/bin/bash
me=${0##*/}
use="
use: $me {number} {operator} [iterations] [scale]
Numbers may include one decimal point.
Operators must be one of: + - * / **
"
while getopts "n:o:i:s:" arg
do case $arg in
n) n="$OPTARG" ;;
o) o="$OPTARG" ;;
i) i="$OPTARG" ;;
s) s="$OPTARG" ;;
*) printf "%s\n" "Invalid argument '$arg' $use";
exit 1;;
esac
done
[[ -n "$n" && -n "$o" ]] || { echo "$use"; exit 1; }
[[ "$n" =~ ^[0-9]+.?[0-9]*$ ]] || { printf "%s\n" "Invalid number '$n' $use"; exit 1; }
[[ "$o" =~ ^([*/^+-]|\*\*)$ ]] || { printf "%s\n" "Invalid operator '$o' $use"; exit 1; }
[[ "${i:=15}" =~ ^[0-9]+.?[0-9.]$ ]] || { printf "%s\n" "Invalid number '$i' $use"; exit 1; }
[[ "${s:=3}" =~ ^[0-9]+$ ]] || { printf "%s\n" "Invalid scale '$s' (must be an integer) $use"; exit 1; }
c=1
while ((c < i))
do printf "%+15s\n" $(bc -l <<< "scale=$s; $n $o $c")
((c++))
done
I'm trying to implement for loops instead of while loops but have no idea how too. This is a while loop script I created. How would I make this into a for loop instead of a while loop? I'm not really understanding how for loops work.
#!/bin/bash
read -p "Number of Papers To Grade:
" numpap
av=$numpap
while [ $av -gt 0 ];
do
av=$(($av - 1))
echo "Enter a Number (1-100): "
read num
if [[ $num -ge 1 && $num -le 100 ]] ; then
echo ""
else
echo "Enter a Number Between 1-100
"
av=$(($av + 1))
total=$(($total - num))
fi
total=$(($total + num))
done
averag=$(($total/$numpap))
echo Average Grade = $averag%
echo "Done"
#!/bin/bash
var=5
for ((value=var; value>0; --value))
do
echo $value
done
This gives the output :
5
4
3
2
1
You can have a look at more ways to write loops using while / for / until : here
I modified your script to run using a for loop:
#!/bin/bash
read -p "Number of Papers To Grade:" numpap
for ((av=numpap; av>0; av--))
do
echo "Enter a Number (1-100): "
read num
if [[ $num -ge 1 && $num -le 100 ]] ; then
echo ""
else
echo "Enter a Number Between 1-100"
av=$(($av + 1))
total=$(($total - num))
fi
total=$(($total + num))
done
averag=$(($total/$numpap))
echo Average Grade = $averag%
echo "Done"
I am learning Bash Shell Scripting as a section from the Linux Foundation LFS101x.2 and there is a Lab to create a simple Bash calculator.
The Lab details are found here:
Lab 5
I'm trying to run the script by:
$ ./bashShellScriptingLab5.sh s 15 5
The error message is:
Welcome to Calculator!
./bashShellScriptingLab5.sh: line 39: syntax error near unexpected token `exit'
./bashShellScriptingLab5.sh: line 39: ` exit 0'
Here is my bashShellScriptingLab5.sh:
#!/bin/bash
echo "Welcome to Calculator!"
if [ $# != 3 ];
then
echo "Usage:"
echo "Please enter a/s/m/d and two integers"
exit 1
fi
addition () {
echo "The result of adding " + $2 + " and " + $3 + " is:"
d = expr $2 + $3
echo $d
}
subtraction () {
echo "The result of subtracting " + $2 + " and " + $3 + " is:"
d = expr $2 - $3
echo $d
}
multiplication () {
echo "The result of multiply " + $2 + " and " + $3 + " is:"
d = expr $2 * $3
echo $d
}
division () {
echo "The result of dividing " + $2 + " and " + $3 + " is:"
d = expr $2 / $3
echo $d
}
if [[ "$1" = "a" ]]
then
addition()
exit 0
elif [[ "$1" = "s" ]]
then
subtraction()
exit 0
elif [[ "$1" = "m" ]]
then
subtraction()
exit 0
elif [[ "$1" = "d" ]]
then
division()
exit 0
else
echo "Usage:"
echo "Please enter a/s/m/d and two integers"
exit 1
fi
Quit a few errors here, I'll run through them and then show an example of a working script.
Firstly you appear to have made some assumptions about how functions work.
Calls to functions do not require the ()
addition()
Also you are trying to use global positional parameter in your functions which will not work as they have their own, so the call to the function should pass in what you want
addition $2 $3
With this in mind the inside of the function will also have to change
echo "The result of adding " + $1 + " and " + $2 + " is:"
As you can see we now use $1 and $2 as we are using the first and second parameter to the function,not the script!
Inside the function there are few more problems
d = expr $2 + $3
Spaces have a purpose in bash so will interfere with the = sign. The command is read as d(function/file/script/exe/whatever) and then the equals is a parameter to this. Thus you cannot have spaces between the = and both sides, so it should be written as
d=expr $2 + $3
Although this will still cause a compile error due to the spaces after expr.So we will need to run this in a subshell to assign it to d
d=$(expr $2 + $3)
Although personally i would just go for bash arithmetic
d=$(($2 + $3))
So if you change all of these in your script it should work, was gonna pad this out a bit more but ran out of time.
Working code
#!/bin/bash
echo "Welcome to Calculator!"
if [ $# != 3 ];
then
echo "Usage:"
echo "Please enter a/s/m/d and two integers"
exit 1
fi
addition () {
echo "The result of adding " + $1 + " and " + $2 + " is:"
d=$(($1 + $2))
echo $d
}
subtraction () {
echo "The result of subtracting " + $2 + " and " + $3 + " is:"
d=$(($1-$2))
echo $d
}
multiplication () {
echo "The result of multiply " + $1 + " and " + $2 + " is:"
d=$(($1*$2))
echo $d
}
division () {
echo "The result of dividing " + $1 + " and " + $2 + " is:"
d=$(($1/$2))
echo $d
}
if [[ "$1" = "a" ]]
then
addition $2 $3
exit 0
elif [[ "$1" = "s" ]]
then
subtraction $2 $3
exit 0
elif [[ "$1" = "m" ]]
then
multiplication $2 $3
exit 0
elif [[ "$1" = "d" ]]
then
division $2 $3
exit 0
else
echo "Usage:"
echo "Please enter a/s/m/d and two integers"
exit 1
fi
To call a function in bash you don't need the parens, those are what's throwing you off. Instead just do
if [[ "$1" = "a" ]]
then
addition
exit 0
elif [[ "$1" = "s" ]]
then
subtraction
exit 0
elif [[ "$1" = "m" ]]
then
multiplication
exit 0
elif [[ "$1" = "d" ]]
then
division
exit 0
else
echo "Usage:"
echo "Please enter a/s/m/d and two integers"
exit 1
fi
Also, for option "m" you had been calling subtraction again, I changed that to multiplication
That will get you past this error, I think you'll find more after that though
Simple Calculator 1.0
clear
echo "(exp=**, div=/, mult=*, add=+, sub=-)"
echo "\"a/b\" returns only quotient (use no spaces)"
echo "\"a / b\" returns quotient and remainder (use spaces)"
echo " "
echo "Welcome to my Simple Calculator"
echo " "
read -p 'Enter a simple calculation: ' -a sC
answer=$((${sC[0]} ${sC[1]} ${sC[2]}))
echo " "
echo " "
if [ "${sC[1]}" != "/" ]
then echo "The answer is equal to $answer"
else answerRemainder=$((${sC[0]} % ${sC[2]}))
echo "The answer is equal to $answer remainder $answerRemainder"
fi
echo " "
echo " "
echo "Thank you for using Simple Calculator 1.0"
echo "Have a nice day!"
No spaces between two expressions returns calculations without remainders:
(exp=**, div=/, mult=*, add=+, sub=-)
"a/b" returns only quotient (use no spaces)
"a / b" returns quotient and remainder (use spaces)
Welcome to my Simple Calculator
Enter a simple calculation: 10/4
The answer is equal to 2
Thank you for using Simple Calculator 1.0
Have a nice day!
Space between "/" will return a remainder:
(exp=**, div=/, mult=*, add=+, sub=-)
"a/b" returns only quotient (use no spaces)
"a / b" returns quotient and remainder (use spaces)
Welcome to my Simple Calculator
Enter a simple calculation: 10 / 4
The answer is equal to 2 remainder 2
Thank you for using Simple Calculator 1.0
Have a nice day!
You can make the first expression as long as you want with no spaces and multiply a second expression that contains addition, subtraction, multiplication, or division:
Enter a simple calculation: 1000/4/2/5 * 4+1
The answer is equal to 101
Enter a simple calculation: 1000/4/2/5 *4-2
The answer is equal to 98
Enter a simple calculation: 1000/4/2/5 * 4*2
The answer is equal to 200
Enter a simple calculation: 1000/4/2/5 * 4/2
The answer is equal to 50
However, Simple Calculator doesn't support remainder division of a second expression that contains any calculations not surrounded with brackets:
If dividing a second expression with calculations the second expression must be surrounded with brackets in order to obtain the correct result:
Enter a simple calculation: 1000/4/2/5 / (4/2)
The answer is equal to 12 remainder 1
Brackets for the second expression are necessary!
1000/4/2/5 / 4/2 <---no brackets will return unpredictable results.
Answer should be 12 remainder 1, but will return 3 remainder 0.
Enter a simple calculation: 1000/4/2/5 / 4/2
The answer is equal to 3 remainder 0
Here in this case for remainder division, the brackets for the second expression are necessary.
I keep getting unexpected End of file error while running a if else statement
#! /bin/bash
echo -e "1: Proband\n 2: mincount\n Enter an option:"
read promin
echo $promin
if ($promin == 1) then
echo -e "Enter the proband file name\n"
read proband_file
echo "$proband_file"
endif
if ($promin == 2) then
echo -e "enter the min count number\n"
read mincount
echo "$mincount mincount"
endif
I tried fi instead of elseif too. But i still get the same error. Can someone help me fix that?
This is how you write an if-statement in bash:
if - then - fi
if [ conditional expression ]
then
statement1
statement2
fi
if - then - else - fi
If [ conditional expression ]
then
statement1
statement2
else
statement3
statement4
fi
if - then - elif - else - fi
If [ conditional expression1 ]
then
statement1
statement2
elif [ conditional expression2 ]
then
statement3
statement4
else
statement5
fi
Example of a conditional expression:
#!/bin/bash
count=100
if [ $count -eq 100 ]
then
echo "Count is 100"
fi
IMPROVED
The if is syntax is not correct. In the if there should be a program (bash internal or external) run, which returns an exit code. If it is 0 then if is true, otherwise it is false. You can use grep or any other utility, like test or /usr/bin/[. But bash has a built-in test and [.
So [ "$var" -eq 1 ] returns 0 if $var equals 1, or return 1 if $var not equals 1.
In your case I would suggest to use case instead of if-then-elif-else-fi notation.
case $x in
1) something;;
2) other;;
*) echo "Error"; exit 1;;
easc
Or even use select. Example:
#!/bin/bash
PS3="Enter an option: "
select promin in "Proband" "mincount";do [ -n "$promin" ] && break; done
echo $promin
case "$promin" in
Proband) read -p "Enter the proband file name: " proband_file; echo "$proband_file";;
mincount) read -p "Enter the min count number: " mincount; echo "$mincount mincount";;
*) echo Error; exit 1;;
esac
This will print the "Enter an option: " prompt and wait until a proper answer is presented (1 or 2 or ^D - to finish the input).
1) Proband
2) mincount
Enter an option: _
Then it checks the answer in the case part. Meanwhile $promin contains the string, $REPLY contains the entered answer. It also can be used in case.
I just changed your code and I think it works now.
I think the problem is you should fi instead of endif...
#!/bin/sh
echo "1: Proband\n2: mincount\nEnter an option:"
read promin
echo $promin
if [ $promin -eq "1" ]
then
echo "Enter the proband file name\n"
read proband_file
echo "$proband_file"
elif [ $promin -eq "2" ]
then
echo "enter the min count number\n"
read mincount
echo "$mincount mincount"
fi
#! /bin/bash
echo -e "1: Proband\n2: mincount\nEnter an option:"
read promin
echo $promin
if (($promin == 1)); then
echo -e "Enter the proband file name\n"
read proband_file
echo "$proband_file"
elif (($promin == 2)); then
echo -e "Enter the min count number\n"
read mincount
echo "$mincount mincount"
fi
I don't know if you need an if-else statement or two if statemnts. The above has an if-else.
If you need two if statements, then insert a line of code below the "echo "$proband_file"" line with the text:
fi
Then replace the line "elif (($promin == 2)); then" with the following code:
if (($promin == 2)); then