Bash sum numbers sequence - bash

I'm trying to SUM a sequence.
Asking for a first number and a second bigger number, the result would be like this:
1st number: 2
2nd bigger number: 6
2+3+4+5+6=20
I'm the whole evening stack, I have to use for and seq
#!/bin/sh
echo -n "Enter number 1: "
read A
echo -n "Enter a number greater o equal than $A: "
read B
J=0
if [ $B -ge $A ]
then
for i in `seq $A $B`
do
RES=$i=$i+$J
#I don't know what to do
done
exit 0
else
echo "wrong"
exit 1
fi
exit 0

This prints out that requested part (I think you already know how to add if/else).
read -p "Enter number 1: " a
read -p "Enter a number greater or equal than $a: " b
high=$(( b-1 ))
sum=0
str=""
for i in $(seq $a ${high}); do
str="${str}${i}+"
sum=$(( j+=i ))
done
sum=$(($sum+$b))
str="${str}${b}=${sum}"
echo $str

Related

Bash script. Accept integer only if is from range

I have bash script with basic arithmetic operations - Addition, Subtraction, Division and Multiplication.
#! bin/bash
input="yes"
while [[ $input = "yes" ]]
do
PS3="Press 1 for Addition, 2 for subtraction, 3 for multiplication and 4 for division: "
select math in Addition Subtraction Multiplication Division
do
case "$math" in
Addition)
echo "Enter first no:"
read num1
echo "Enter second no:"
read num2
result=`expr $num1 + $num2`
echo Answer: $result
break
;;
Subtraction)
echo "Enter first no:"
read num1
echo "Enter second no:"
read num2
result=`expr $num1 - $num2`
echo Answer: $result
break
;;
Multiplication)
echo "Enter first no:"
read num1
echo "Enter second no:"
read num2
result=`expr $num1 * $num2`
echo Answer: $result
break
;;
Division)
echo "Enter first no:"
read num1
echo "Enter second no:"
read num2
result=$(expr "scale=2; $num1/$num2" | bc)
echo Answer = $result
break
;;
*)
echo Choose 1 to 4 only!!!!
break
;;
esac
done
done
How to make that values for #num1 and #num2 are accepted only if they are numbers in certain range. For example 0 to 10. So if I enter for $num1 or $num2 lets say 500 there will be message to enter valid value?
You can create a simple function to get a number in range:
get_number() {
local lo=$1 up=$2 text=${3:-Enter a number: } num
shopt -s extglob
until
read -p "$text" num
[[ $num = ?(-)+([0-9]) ]] && (( $lo <= 10#$num && 10#$num <= $up ))
do
echo "Invalid input!" >&2
done
echo "$((10#$num))"
}
num1=$(get_number 10 15 "Enter first number: ")
num2=$(get_number -10 20) # use default prompt
Works for integers only. You might also consider inputting the numbers before the case command to avoid redundant code.

Division by zero using shell

I'm writing a shell program using while commands to prevent division by zero and to exit the program when the user types 99. Everytime i run it i get an error for the input of the second number which in turn does not give me the answer. Below is my attempt at this problem:
#!/bin/bash
firstNum=0
secondNum=0
answer=0
while true firstNum != 99, secondNum != 99 do
read -p "Enter first number" firstNum
read -p "Enter second number" secondNum
echo "first num $firstNum"
echo "second Num $secondNum"
if ["$secondNum" = "0"]
then
exit 1
else
echo "first number / second Number = $((firstNum/secondNum))"
echo "Answer = $answer"
fi
do
exit
done
And the following is the error message that i get
./example.sh: 10: ./example.sh: [2: not found
Any help at all is greatly appreciated.
Thanks
Looks like a few typos.
Replace this:
if ["$secondNum" = "0"] then
exit 1
then
echo "1st number / 2nd number = $((firstNum/secondNum))"
echo "Answer = $answer"
fi
with this:
if [ "$secondNum" = "0" ]
then
exit 1
else
echo "1st number / 2nd number = $((firstNum/secondNum))"
echo "Answer = $answer"
fi
Bash is finicky. Ensure then is on the next line and not same line as the if, you also had then instead of else on your 3rd line.
Your code can be simplified
while true; do
read -p "Enter first number: " firstNum
[[ "$firstNum" -eq 99 ]] && break
read -p "Enter second number: " secondNum
case "$secondNum" in
99) break ;;
0) echo "div by zero, try again"; continue ;;
esac
echo "first number / second Number = $(bc -l <<< "$firstNum/$secondNum")"
done
I'm calling out to bc to get floating point arithmetic. With the shell you're limited to integers only.
<<< is a "here-string", a string to pass to bc's stdin
Your code looks pretty good to me, but I changed the POSIX shell test around a bit to test for values less than 99 instead of 99 itself. And there was a stray do near the bottom of the script which I removed. Bash has [[]] style test syntax too which you may want to switch to at some point.
#!/bin/bash
firstNum=0
secondNum=0
answer=0
while [ "$firstNum" -lt 99 -a "$secondNum" -lt 99 ]
do
read -p "Enter first number " firstNum
read -p "Enter second number " secondNum
printf "first num $firstNum\n"
printf "second Num $secondNum\n"
if [ "$secondNum" = 0 ]
then
printf "$secondNum was a zero, exiting!\n"
exit 1
else
printf "first num / second Num = \$(($firstNum / $secondNum))\n"
answer=$(( firstNum / secondNum))
printf "Answer = $answer\n"
fi
done
If you are interested in learning the Bash test syntax [[]] (it's a bit more powerful than POSIX shell's test(1) []) here is an example which uses it:
#!/bin/bash
firstNum=0
secondNum=0
answer=0
while [[ "$firstNum" < 99 && "$secondNum" < 99 ]]
do
read -p "Enter first number " firstNum
read -p "Enter second number " secondNum
printf "first num $firstNum\n"
printf "second Num $secondNum\n"
if [[ "$secondNum" == 0 ]]
then
printf "$secondNum was a zero, exiting!\n"
exit 1
else
printf "first num / second Num = \$(($firstNum / $secondNum))\n"
answer=$(( firstNum / secondNum))
printf "Answer = $answer\n"
fi
done
It may also be advisable to move the tests into the body of the while loop and instead use the convention 'while [[ 1 ]]' to create a continuous loop. Here is an example doing that (using bash test syntax [[]]) and using bc so the script supports floating point arithmetic:
#!/bin/bash
firstNum=0
secondNum=0
answer=0
while [[ 1 ]]
do
read -p "Enter first number " firstNum
read -p "Enter second number " secondNum
printf "first num $firstNum\n"
printf "second Num $secondNum\n"
case "$firstNum" in
99) printf "Invalid values\n"
exit 1
;;
esac
case "$secondNum" in
99) printf "Invalid values\n"
exit 1
;;
0) printf "Invalid values\n"
exit 1
;;
esac
answer=$(printf "$firstNum / $secondNum\n" | bc -l)
printf "Floating point supported answer using bc: = $answer \n"
done

How to get the factors of a given number in Unix?

I have this concern, when getting the factors of a number. My code gives me the total numbers of all factors of a number.What I want is it should only display the factors of that number, not the total. For example I input 9 the output should be 1,3 and 9.
My code
echo -n " enter a no. "
read n
i=1
mul=1
until [ $i -gt $n ]
do
mul=`expr $mul \* $i `
i=`expr $i + 1 `
done
echo " factorial of $n is $mul "
Assuming that the user enters the number in its simplest form, e.g. 9 instead of 09.0, this works:
echo -n " enter a no. "
read n
for i in $(seq 1 $n)
do
[ $(expr $n / $i \* $i) == $n ] && echo $i
done
though a bit slowly for large numbers.

How to redirect variable into text file then sort alphabetical

My script is to ask for input 1 upper case at a time and end with 0 invalid input will need to be displayed and display the first valid upper letter.
#! /bin/sh
count=0
until [[ $n =~ 0 ]]; do
echo Inputs:
read n
if [[ $n =~ ^[A-Z]$ ]]; then
count=`expr $count + 1`
echo $n | sort > out.txt
fi
done
echo The total number of valid input letters:
echo $count
echo " "
echo The first valid input:
head -n 1 /filepath/out.txt
Output:
Inputs:
B
Inputs:
A
Inputs:
C
Inputs:
0
The total number of valid input letters:
3
The first valid input:
C
Question: It should result in A.
Any help will be appreciated.
This line:
echo $n | sort > out.txt
always zaps the file out.txt with just the latest input. Maybe you should use:
cp /dev/null out.txt # Before the loop
echo $n | sort -o out.txt out.txt -
The cp command creates an empty file. The sort command reads the existing file out.txt and its standard input (the new line), sorts the result and writes it out over out.txt.
This is OK for short inputs; it isn't very efficient if it needs to scale to thousands of lines.
Also, in Bash, you don't need to use expr for arithmetic:
((count++))
Use the following code.
#! /bin/sh
count=0
>out.txt
until [[ $n =~ 0 ]]; do
read -p 'Inputs: ' n
if [[ $n =~ ^[A-Z]$ ]]; then
count=`expr $count + 1`
echo $n >> out.txt
fi
done
echo The total number of valid input letters:
echo $count
echo " "
echo The first valid input:
sort out.txt |head -n 1
Output:
Inputs: B
Inputs: A
Inputs: C
Inputs: 0
The total number of valid input letters:
3
The first valid input:
A
Since you want only the smallest (in alphabet order) valid input, you don't need sort. Here's an alternative answer not using sort but just keep the smallest valid input:
#!/bin/sh
count=0
until [[ $n =~ 0 ]]; do
echo Inputs:
read n
if [[ $n =~ ^[A-Z]$ ]]; then
((count++))
if [ -z $first ] || [ `expr $n \< $first` -eq 1 ]; then
first=$n
fi
fi
done
echo The total number of valid input letters:
echo $count
echo " "
echo The first valid input:
echo $first

Shell script read user input

I got stuck on this shell script code where it requires user to enter the group number and find the largest and the average out of that group number.
My code ATM only works with passing the group number as a command-line argument. How to prompt for the group number as user input?
read n
if [ $n -ge 1 ]; then
sum=0
count=$n
max=-1000
if [ $max -lt $1 ]; then
max=$1
fi
while [ $n -ge 1 ]; do
case $1 in
[0-9] | [1-9][0-9])
sum=`expr $sum +$1`;;
-[1-9] | -[1-9][0-9])
sum=`expr $sum + $1`;;
done
if [ $count -gt 0 ]; then
avg=`expr $sum / $count`
echo The largest number is $max
echo The average number is $avg
From your comments it seems you would like to read values from stdin rather than from the command line. To do that in Bash you use the read builtin:
read -ep "Enter group number: " group
printf "Entered %d\n" $group
For interactive prompting it is usually put in the test part of a while loop where you can break if the input is invalid:
shopt -s extglob
while read -ep "Enter group number: " group; do
case $group in
?(-)+([0-9])) # valid input
# compute average here
*) break ;; # not valid input
esac
done
See help read for more information.
You're working way too hard, and your script is way too verbose. Try:
#!/bin/sh
test $# -gt 0 || { echo Please enter at least one argument >&2; exit 1; }
max=0
for x; do
test "$max" -lt $x && max=$x
test $? -gt 1 && exit 1
: $(( count += 1 ))
: $(( sum += x ))
done
echo max = $max
printf "avg = "
expr $sum / $count
Since you used expr in your script, I'm doing the same, but be aware that all of the arithmetic will be done in the integers (so the reported average will be the greatest integer less than the actual average, and non-integer input will be considered an error). This solution relies on test returning a value greater than 1 when it encounters an error (eg, non integer input), which is the behavior specified by the open group.
Also note that this puts the error message on stderr (where error messages belong) and returns a non-zero value to indicate that the script failed.

Resources