Sum digits of a number while greater than 2 digits - bash

The challenge is to sum the digits of a given number till the result has only one digit. Let say the number is "999" (9+9+9=27, 2+7=9). This is what I did till now.
#!/bin/bash
set +m
shopt -s lastpipe
NUMBER=999
DIGITS=`echo "${#NUMBER}"`
FINALSUM=0
if [ "$DIGITS" -gt 0 ] && [ "$DIGITS" -gt 1 ]; then
grep -o . <<< "${NUMBER}" | while read DIGIT; do
declare -x FINALSUM="$(($FINALSUM+$DIGIT))"
done
echo $FINALSUM
else
echo $SOMA
fi

A bit slow for large numbers:
function sumit {
i="$1"
while [ "$i" -gt 10 ]; do
(( i=i%10 + i/10 ))
done
echo "$1 => $i"
}
# Test
for i in 10 15 999 222 2229; do
sumit $i
done

Can an awk-ward guy join in?
$ awk -v i=999 '
BEGIN {
while( split(i,a,"") > 1) {
i=0;
for( j in a ) i+=a[j]
}
print i
}'
9

Related

Problem in shell code to find happy prime number

This is my code to find happy prime number, I don't know why it is giving error.
#!/bin/bash
happy(){
rem = $0
sum = $0
while [ $result -gt 0 ];
do
rem = $((result%10))
p = $((rem*rem))
sum = $((sum + p))
result = $((result/10))
done
return $sum
}
echo "Enter a number"
read num
for (( i=1; i<101; i++ ))
do
result=$i
while [ $result -ne 0 && $result -ne 4 ];
do
happy $result
done
if [ $?==1 ]
then echo "happy number"
else
echo "not a happy number"
fi
done
I see lots of syntax errors and some logical errors in your script.
This should be a fixed version (works at least for 13 and 4 :))
Errors I've found:
rem = $0 and similar: the spaces around assignments are not allowed in bash,
rem = $0: you assign a value that is never used,
rem = $0 and sum = $0 the first argument passed to the function is $1 not $0,
the input number is assigned to num but never used,
the exit condition from the for and while loops is broken,
...
#!/bin/bash
happy()
{
result=$1
sum=0
while [ $result -gt 0 ]; do
rem=$(( result % 10 ))
p=$(( rem * rem ))
sum=$(( sum + $p ))
result=$(( result / 10 ))
done
echo "$sum"
}
echo "Enter a number"
read num
result=$num
for (( i=1; i<101; i++ )) do
result=$(happy $result)
if [ $result == 1 ]; then
echo "$num is a happy number"
exit
fi
done
echo "$num is not a happy number"

how to print prime numbers using for loop in shell script

I want to print prime numbers using for loop in shell script. Please provide some suggestions.
actually I could able to print odd numbers from range of 1 to 100, but now I am unable to print prime numbers. Provide some script to print prime numbers
# cat prime.sh
#!/bin/bash
for ((i=1; i<=100; i++))
do
output=$(( $i % 2))
if [ $output -ne 0 ]
then
echo "We got odd numbers: $i"
fi
done
The below code returns the list of prime numbers within a specified range.
the below command returns the prime numbers between 10 to 30
./filename.sh 10 30
#!/bin/bash
# Check if a number is prime
# function to return whether prime or not
check_prime() {
current_number=$1
flag=0
i=2
while test $i -le `expr $current_number / 2`
do
if test `expr $current_number % $i` -eq 0
then
flag=1
fi
i=`expr $i + 1`
done
if test $flag -eq 0
then echo $current_number
fi
}
# Assign From and to number
from_number=$1
to_number=$2
for (( number=$from_number; number<=$to_number; number++ ))
do
check_prime $number
done
This code will Print all prime numbers upto given number & also print count of it
hope it helps !!
#!/bin/bash
echo "enter a number upto which you want the prime numbers"
read num
count=0
for (( n=2; n<=$num; n++ ))
do
t=1
if [ $n -lt 2 ]
then echo "Please give other numbers than 0 and 1"
else
#echo $n
for (( i=2; i<$n; i++ ))
do
#echo $n
if (($n%i==0))
then
#echo "$n is not prime number"
t=0
break;
fi
done
#echo $t
if [ $t == 1 ]
then
echo "$n is a prime number"
count=`expr $count + 1`
fi
fi
done
echo "Total prime numbers upto $num are $count "

AWK int comparison statements not working

I am using Hacker Rank challenges to teach myself BASH, and I'm in need of some advice.
I'm specifically trying to solve this challenge: Apple and Oranges by nabila_ahmed
I need to read in multiple lines of ints separated by spaces, on multiple lines. I decided to use awk to do this because it seems a lot more efficient in memory storage than using read. (I tried a couple of solutions using read and they timed out, because the test cases are really big.)
Example input:
7 11
5 15
3 2
-2 2 1
5 -6
This is my first attempt in bash and it timed out:
row=0
while read line || [[ -n $line ]]; do
if [ "$row" -eq 0 ]
then
column=0
for n in $line; do
if [ "$column" -eq 0 ]
then
housePos1=$n
elif [ "$column" -eq 1 ]
then
housePos2=$n
fi
((column++))
done
# Calculate house min and max
if [ "$housePos1" -gt "$housePos2" ]
then
minHousePos=$housePos2
maxHousePos=$housePos1
else
minHousePos=$housePos1
maxHousePos=$housePos2
fi
elif [ "$row" -eq 1 ]
then
column=0
for n in $line; do
if [ "$column" -eq 0 ]
then
appleTreePos=$n
elif [ "$column" -eq 1 ]
then
orangeTreePos=$n
fi
((column++))
done
elif [ "$row" -eq 3 ]
then
applesInHouse=0
for n in $line; do
# Calculate the apple's position
let applePos=$((appleTreePos + n))
# If the apple's position is within the houses position, count it
if [ "$applePos" -ge "$minHousePos" ] && [ "$applePos" -le "$maxHousePos" ]
then
((applesInHouse++))
fi
done
elif [ "$row" -eq 4 ]
then
orangesInHouse=0
for n in $line; do
# Calculate the apple's position
let orangePos=$((orangeTreePos + n))
# If the apple's position is within the houses position, count it
if [ "$orangePos" -ge "$minHousePos" ] && [ "$orangePos" -le "$maxHousePos" ]
then
((orangesInHouse++))
fi
done
fi
((row++))
done
echo "$applesInHouse"
echo "$orangesInHouse"
Here is my second attempt in bash, even more of the solutions timed out:
x=0;y=0;read -r s t;read -r a b;read -r m n;
for i in `seq 1 $m`; do
if [ "$i" -lt "$m" ]
then
read -d\ z
else
read -r z
fi
if [ "$((a+z))" -ge "$s" ] && \
[ "$((a+z))" -le "$t" ]
then
((x++))
fi
done
for i in `seq 1 $n`; do
if [ "$i" -lt "$n" ]
then
read -d\ z
else
read -r z
fi
if [ "$((b+z))" -ge "$s" ] && \
[ "$((b+z))" -le "$t" ]
then
((y++))
fi
done
echo $x; echo $y
Here's where I am at in debugging my solution using awk...
awk -v RS='[-]?[0-9]+' \
'{
if(word==$1) {
counter++
if(counter==1){
s=RT
}else if(counter==2){
t=RT
}else if(counter==3){
a=RT
}else if(counter==4){
b=RT
}else if(counter==5){
m=RT
}else if(counter==6){
n=RT
}else{
counter2++
if(counter2<=m){
print "Apples:"
print a+RT
print a+RT>=s
print a+RT<=t
applecount++
}
if(counter2>m && counter2<=m+n){
print "Oranges:"
print b+RT
print b+RT>=s
print b+RT<=t
orangecount++
}
}
}else{
counter=1
word=$1
}
}
END {
print "Total Counts:"
print applecount
print orangecount
}
'
Here is the output from that script when using the sample input
Apples:
3
0
0
Apples:
7
1
0 <-- This is the problem! (7 is less than or equal to 11)
Apples:
6
0
0
Oranges:
20
0
0
Oranges:
9
1
0 <-- This is also a problem! (9 is less than or equal to 11)
Total Counts:
3
2
As you can see, I'm getting some of the wrong comparisons...
ANSWER
(mostly courtesy of #glenn-jackman)
apples_oranges() {
local s t a b m n d
local -a apples oranges
local na=0 nb=0
{
read s t
read a b
read m n
read -a apples
read -a oranges
} < "$1"
for d in "${apples[#]}"; do
(( s <= a+d && a+d <= t )) && ((na++))
done
echo $na
for d in "${oranges[#]}"; do
(( s <= b+d && b+d <= t )) && ((nb++))
done
echo $nb
}
apples_oranges /dev/stdin
I'd do this with bash
apples_oranges() {
local s t a b m n d
local -a apples oranges
local na=0 nb=0
{
read s t
read a b
read m n # unused
read -a apples
read -a oranges
} < "$1"
for d in "${apples[#]}"; do
(( a+d >= s )) && ((na++))
done
echo $na
for d in "${oranges[#]}"; do
(( b-d <= t )) && ((nb++))
done
echo $nb
}
apples_oranges input.txt
this may get you started...
$ awk '
NR==1{split($0,house)}
NR==2{split($0,trees)}
NR==3{split($0,counts)}
NR==4{split($0,apples)}
NR==5{split($0,oranges)}
END{for(i in apples)
if(trees[1]+apples[i]>=house[1] && trees[1]+apples[i]<=house[2]) a++; print a}' file

Issue with program check if the number is divisible by 2 with no remainder BASH

I tried to write a program to see if the count divisible by 2 without a remainder
Here is my program
count=$((count+0))
while read line; do
if [ $count%2==0 ]; then
printf "%x\n" "$line" >> file2.txt
else
printf "%x\n" "$line" >> file1.txt
fi
count=$((count+1))
done < merge.bmp
This program doesnt work its every time enter to the true
In the shell, the [ command does different things depending on how many arguments you give it. See https://www.gnu.org/software/bash/manual/bashref.html#index-test
With this:
[ $count%2==0 ]
you give [ a single argument (not counting the trailing ]), and in that case, if the argument is not empty then the exit status is success (i.e. "true"). This is equivalent to [ -n "${count}%2==0" ]
You want
if [ "$(( $count % 2 ))" -eq 0 ]; then
or, if you're using bash
if (( count % 2 == 0 )); then
Some more "exotic" way to do this:
count=0
files=(file1 file2 file3)
num=${#files[#]}
while IFS= read -r line; do
printf '%s\n' "$line" >> "${files[count++ % num]}"
done < input_file
This will put 1st line to file1, 2nd line to file2, 3rd line to file3, 4th line to file1 and so on.
awk to the rescue!
what you're trying to do is a one-liner
$ seq 10 | awk '{print > (NR%2?"file1":"file2")}'
==> file1 <==
1
3
5
7
9
==> file2 <==
2
4
6
8
10
try
count=$((count+0))
while read line; do
if [ $(($count % 2)) == 0 ]; then
printf "%x\n" "$line" >> file2.txt
else
printf "%x\n" "$line" >> file1.txt
fi
count=$((count+1))
done < merge.bmp
You have to use the $(( )) around a mod operator as well.
How to use mod operator in bash?
This will print "even number":
count=2;
if [ $(($count % 2)) == 0 ]; then
printf "even number";
else
printf "odd number";
fi
This will print "odd number":
count=3;
if [ $(($count % 2)) == 0 ]; then
printf "even number";
else
printf "odd number";
fi

how to extract numbers from this echo into separate variables?

Sorry about bits and snippit of information
So I am writing an average shell script program
so if use inputs
echo 1 3, .... | sh get_number
I would have to pull the numbers seperated by spaces from echo to be
var1 = 1, var2= 3, etc.
I tried
#!/bin/sh
sum=0
for i in $*
do
sum=`expr $sum + $i`
done
avg=`expr $sum / $n`
echo Average=$avg
but doesnt work....
do I include a read here?
also how would I do
sh get_number <file1>, <file2>... to grab numbers in them and sum them
in shell script?
Thanks
Sounds like you are looking for the read shell builtin:
% echo "1 2 3 4" | read a b stuff
% echo $b
2
% echo $stuff
3 4
To fix up your code:
for i in $*; do
sum=$(( sum + i ))
n=$(( n + 1 ))
done
echo "Average=$(( sum / n ))"
#!/bin/sh
while [ $# -gt 0 ]; do
(( i++ ))
(( sum += $1 ))
shift
done
echo "Average=$(( sum/i ))"
Note: This fails in dash which is the closest shell I could find to a real sh.
An example of reading values from files passed as command line arguments or from lines read from stdin:
add_to_sum() {
set $*
while [ $# -gt 0 ]; do
I=`expr $I + 1`
SUM=`expr $SUM + $1`
shift
done
}
I=0
SUM=0
if [ $# -gt 0 ]; then
# process any arguments on the command line
while [ $# -gt 0 ]; do
FILE=$1
shift
while read LINE; do
add_to_sum "$LINE"
done < "$FILE"
done
else
# if no arguments on the command line, read from stdin
while read LINE; do
add_to_sum "$LINE"
done
fi
# be sure not to divide by zero
[ $I -gt 0 ] && echo Average=`expr $SUM / $I`

Resources