In bash, i need to add (sum) one to a five digit number. The 5 digit number is extracted from a string.
Ex:
To get the 5 digits from the string that resides in a txt file:
#!/bin/bash
SUBSTRING_LATEST=$(echo $MYFILE | cut -c15-19)
That line returns: 00016
I'm trying to sum 1 to that number and get the final result like 00017
Tried this, but no luck
SUM_FINAL=$((SUBSTRING_LATEST + 1))
But that returns 15
I really appreciate any help
Thanks
You can use base 10 arithmetic otherwise any number starting with a 0 is interpreted as octal number:
s='00016'
printf "%05d" $((10#$s + 1))
00017
Using octal arithmetic you will get:
printf "%05d" $(($s + 1))
00015
Related
Greeting
I am currently developing a function thaT converts each decimal to binary without using awk sed printf xxd od perl ibase, obase , bc
However, the function managed to convert into decimal to binary but for some reason, it is outputting the "expr:Division by Zero" at the end of the converted binary
I have tried to remove expr and set as a normal formula but it distributed another error so i have no choice to stuck with this since it is the closet thing that converts decimal to binary
for i in $d do #$d is the decimal
num = $d #decimal number
div = 128 #it is the power number (we should start dividing by 128)
sec = 0 #to run the loop 8 times
while [[ $seq -ne 9 ]]
do
bin=`expr $num / $div`
echo -n "$bin" # we can add the replacing x and space here
rem=`expr $num % $div` # gets the remainder
div=$(expr $div / 2) #to get the decreasing power of 2
num=$rem #next the num should be equal to the remainder
sec=$(sec + 1)
done
done
#OUTPUT
Output : 11111000expr:division by zero
Any hint will be much appreciated
There are lots of things wrong here, starting with simple syntax. If you want to convert from decimal representation to binary representation using pure bash, you can use this script:
#!/bin/bash
dec=123456 # for example
bin=
n=$dec
while ((n)); do
bin=$((n & 1))$bin
((n >>= 1))
done
echo "$dec(decimal) = ${bin:-0}(binary)"
This should work for all non-negative integers which can be represented in 63 bits (unless your bash version is very old).
This question already has answers here:
How do I use floating-point arithmetic in bash?
(23 answers)
Bash - Calculate the Average of Numbers Inputted
(4 answers)
Closed 1 year ago.
How do you perform floating-point math over variables in bash
the output I get is an integer like number
#! /bin/bash
# finding the average of n numbers
avg=0
read -p "" n
for (( i = 0; i < $n; i++ ))
do
read x
((avg = $avg + $x ))
done
#printf %.3f "$(( avg / n )) "
the goal is to show up to 3 decimal places
3
4
5
6
./avg.sh: line 22: printf: 5 : invalid number
5,000
I tried using | bc but I am missing sth
You can replace the entire loop with awk, which does floating-point math natively:
read -p "" n
awk -v n="$n" '{sum+=$1}; NR==n {printf "%.3f\n", sum/n; exit}'
Explanation: -v n="$n" copies the shell variable n into an awk variable with the same name. {avg+=$1} adds each line of input (well, the first "field" of each line) to a running sum. NR==n {printf "%.3f\n", sum/n; exit} means when it hits the nth line, it prints sum/n to three decimal places and exits.
Found this useful question
Added this section after the for loop
var=$(echo "scale=3; $avg / $n" | bc -l)
echo $var
Here is how you can compute the average of n numbers with POSIX shell arithmetic and have 3 or more decimals:
#!/usr/bin/env sh
decimals=3
# The decimal precision is one digit more than the display decimals,
# so it can have an accurate rounding when formatting.
# The precision factor is 10^(decimals + 1).
precision_factor=$(printf '1%0*d' $((decimals + 1)) 0)
average () {
# Multiply the sum of the arguments by the precision factor,
# and divide by the number of arguments.
# With IFS=+ $* expands to the sum of the arguments $1+$2+$3...
# Example, arguments 5 8 1 7 will expand to 5+8+1+7 because IFS is +
IFS=+ average=$(((($*)*precision_factor)/$#))
# The integer part is the average divided by the precision factor.
integer_part=$((average/precision_factor))
# The decimal part is the average head-stripped from the integer part.
decimal_part=${average#$integer_part}
# Assemble a C-locale (decimal point) string for floating-point average.
float_average="$integer_part.$decimal_part"
# Bash consider floating point arguments to printf must be formatted
# to the current locale. So specify we use the C-locale.
LC_NUMERIC=C printf 'Average: %.*f\n' "$decimals" "$float_average"
}
if [ $# -eq 0 ]; then
printf 'Enter a set of numbers: '
read -r input
average $input
else
average "$#"
fi
I need to zero-pad a sequence of numbers in a loop in Bash. I know how to do it with
seq -f "%03g" 5
or the comparable printf approach, also
for index in {003..006}
The problem I did not find an answer to is that I need the number of digits to be a variable:
read CNT
seq -f "%0$CNTd" 3 6
Will return an error
seq: das Format »%0“ endet mit %
I have not found any way to insert a variable in a format string or any other way to produce a zero-padded sequence where the number of digits comes from a (user-provided) variable.
I think you want seq, but did you know the * operator in printf?
printf "%0*d\n" ${CNT} 5
A variable name (CNT) should be enclosed in curly braces when it is followed by a character (d) which is not to be interpreted as part of its name,
seq doesn't support %d, you should use %g.
$ read -r CNT
$ seq -f "%0${CNT}g" 3 6
00003
00004
00005
00006
I would like to create four strings, each with a random length, but their total length should be 10. So possible length combinations could be:
3 3 3 1
or
4 0 2 2
Which would then (respectively) result in strings like this:
111 222 333 4
or
1111 33 44
How could I do this?
$RANDOM will give you a random integer in range 0..32767.
Using some arithmetic expansion you can do:
remaining=10
for i in {1..3}; do
next=$((RANDOM % remaining)) # get a number in range 0..$remaining
echo -n "$next "
((remaining -= next))
done
echo $remaining
Update: to repeat the number N times, you can use a function like this:
repeat() {
for ((i=0; i<$1; i++)); do
echo -n $1
done
echo
}
repeat 3
333
Here is an algorithm:
Make first 3 strings with random length, which is not greater than sum of lenght (each time substract it). And rest of length - it's your last string.
Consider this:
sumlen=10
for i in {1..3}
do
strlen=$(($RANDOM % $sumlen)); sumlen=$(($sumlen-$strlen)); echo $strlen
done
echo $sumlen
This will output your lengths, now you can create strings, suppose you know how
alternative awk solution
awk 'function r(n) {return int(n*rand())}
BEGIN{srand(); s=10;
for(i=1;i<=3;i++) {a=r(s); s-=a; print a}
print s}'
3
5
1
1
srand() to set a randomized seed, otherwise will generate the same random numbers each time.
Here you can combine the next task of generating the strings into the same awk script
$ awk 'function r(n) {return int(n*rand())};
function rep(n,t) {c="";for(i=1;i<=n;i++) c=c t; return c}
BEGIN{srand(); s=10;
for(j=1;j<=3;j++) {a=r(s); s-=a; printf("%s ", rep(a,j))}
printf("%s\n", rep(s,j))}'
generated
1111 2 3 4444
I am making a shell script that takes a single number (length is unimportant) from the command line and adds the digits of it together. I thought I had it, but it won't work and either displays "0+3+4+5" if the command input is 345 or it displays the variables when I use expr to add them.
#!/bin/bash
sum=0
i="$(expr length $1)"
s=$1
for i in $(seq 0 $((${#s} - 1))); do
value=${s:$i:1}
typeset -i value
sum=$sum+$value
done
echo $sum
Also doesn't work when I replace it with sum='expr $sum + $value'
any ideas?
What you are looking for is sum=$(($sum+$value)).
#!/bin/bash
expr $(echo $1| sed 's/./& + /g;s/..$//')
For example, if the argument is 12345, this translates it to the string 1 + 2 + 3 + 4 + 5 and uses expr to evaluate it.