Kind of new to bash scripting and is having trouble with the below code.
I am trying to compare the array number with the number you have input from the "read ans" the problem is mostly comparing decimal numbers
BGpercent=(0 99 99.3 99.6 99.8 100)
BGpoint=(0 1 2 3 4 5)
read ans
for (( c=${#BGpercent[#]}; c>=0; c-- ))
do
echo "${BGpercent[$c]}"
if [ "${BGpercent[$c]}" <= "$ans" ];
then
result=${BGpoint[$c]}
break
fi
done
echo $result | bc -lstrong text
Error - ./testscript.sh: =: No such file or directory
I guess the problem is in your if check (floating point comparison).
#!/bin/bash
BGpercent=(0 99 99.3 99.6 99.8 100)
BGpoint=(0 1 2 3 4 5)
read ans
for (( c=$[ ${#BGpercent[#]} - 1 ] ; c>=0; c-- ))
do
if (( $(echo "${BGpercent[$c]} <= $ans" |bc -l) ));
then
result=${BGpoint[$c]}
break
fi
done
Also, the variable c value must be decremented in the beginning, else it will contain an invalid index value. I am not sure what you intent to do with the last line (echo $result | bc -lstrong text)
BGpercent=(0 99 99.3 99.6 99.8 100)
BGpoint=(0 1 2 3 4 5)
echo " Write in your number:"
read number
for (( c=${#BGpercent[#]}-1; c>-1; c-- ))
do
echo ${BGpercent[$c]}
bool=echo "if (${BGpercent[$c]} <= ${number}) 1" | bc
if [ "$bool"1 -eq 11 ] ; then
result=${BGpoint[$c]}
break
fi
Related
Please tell why printing odd numbers in bash script with the following code gives the error:
line 3: {1 % 2 : syntax error: operand expected (error token is "{1 % 2 ")
for i in {1 to 99}
do
rem=$(( $i % 2 ))
if [$rem -neq 0];
then
echo $i
fi
done
This is working example:
for i in {1..99}
do
rem=$(($i % 2))
if [ "$rem" -ne "0" ]; then
echo $i
fi
done
used for loop have a typo in minimum and maximum number, should be {1..99} instead of {1 to 99}
brackets of the if statement needs to be separated with whitespace character on the left and on the right side
Comparision is done with ne instead of neq, see this reference.
As already pointed out, you can use this shell checker if you need some clarification of the error you get.
Not really sure why nobody included it, but this works for me and is simpler than the other 'for' solutions:
for (( i = 1; i < 100; i=i+2 )); do echo $i ; done
To print odd numbers between 1 to 99
seq 1 99 | sed -n 'p;n'
With GNU seq, credit to gniourf-gniourf
seq 1 2 99
Example
$ seq 1 10 | sed -n 'p;n'
1
3
5
7
9
if you reverse it will print even
$ seq 1 10 | sed -n 'n;p'
2
4
6
8
10
One liner:
for odd in {1..99..2}; do echo "${odd}"; done
Or print in a cluster.
for odd in {1..99..2}; do echo -n " ${odd} "; done
Likewise, to print even numbers only:
for even in {2..100..2}; do echo "${even}"; done
OR
for even in {2..100..2}; do echo -n " ${even} "; done
Replace {1 to 99} by {1..99}.
for (( i=1; i<=100; i++ ))
do
((b = $i % 2))
if [ $b -ne 0 ]
then
echo $i
fi
done
for i in {1..99}
do
rem=`expr $i % 2`
if [ $rem == 1 ]
then
echo "$i"
fi
done
for i in {0..49}
do
echo $(($i*2+1))
done
Is there a way to get rid of having to create 4 different do-while statements for each variable? For example, I would like to calculate 1!-7! w/o initializing 7 diff. variables and initializing 7 different variables. Is this possible?
Below is an example of how I would like the program to initiate and what the output should be
./filename.sh 1 2 3 4 5 6 7
The factorial 1! is 1
The factorial 2! is 2
The factorial 3! is 6
The factorial 4! is 24
…
Code:
#!/bin/bash
on1=0 #initiating the 4 variables
on2=0 #possible to compress these into 1 variable?
on3=0
on4=0
fact1=1
fact2=1
fact3=1
fact4=1
echo -n "Enter numbers to find factorial : " # gets user input of 4 #s
read n1 n2 n3 n4
on1=$n1
on2=$n2
on3=$n3
on4=$n4
while [ $n1 -ge 1 ] # calculates first factorial
do #possible to only make 1 loop?
fact1=`expr $fact1 \* $n1`
n1=`expr $n1 - 1`
done
while [ $n2 -ge 1 ] # calculates second factorial
do
fact2=`expr $fact2 \* $n2`
n2=`expr $n2 - 1`
done
while [ $n3 -ge 1 ] #calculates third factorial
do
fact3=`expr $fact3 \* $n3`
n3=`expr $n3 - 1`
done
while [ $n4 -ge 1 ] # calculates fourth factorial
do
fact4=`expr $fact4 \* $n4`
n4=`expr $n4 - 1`
done
echo "The factorial $on1! is $fact1" # outputs the four factorials
echo "The factorial $on2! is $fact2" #possible to make only 1 echo?
echo "The factorial $on3! is $fact3"
echo "The factorial $on4! is $fact4"
Use a loop to process each of the arguments.
#!/bin/bash
while [ $# -gt 0 ]
do
n=$1
on=$n
fact=1
while [ $n -ge 1 ]
do
fact=$(expr $fact \* $n)
n=$(expr $n - 1)
done
echo "The factorial of $on is $fact"
shift # go to the next argument
done
Just for fun, I tried a recursive solution:
#!/bin/zsh
function fact {
if (($1 < 2))
then
echo 1
else
expr $1 '*' $(fact $(($1-1)))
fi
}
for arg
do
fact $arg
done
I first thought, it would blow up soon due to stack overflow, but it calculated happily even pretty large values (such as 200!) in quite short time (in zsh; didn't try it with other shells)!
I want to use modulo in a Bash script, but the result is always to low.
I need something like this: days = jdn mod p
this is what i have:
#!/bin/bash
if [ $# -ne 2 ]
then
echo "Fout, syntaxis: $0 maand(in cijfers) jaar"
exit 1
fi
a=$(echo "14 - $1"|bc)
y=$(echo "$2 + 4800 - $a"|bc)
m=$(echo "12 * $a - 3 + $1"|bc)
jdn=$(echo "scale=2;1 + (153 * $m +2)/5 + 365 * $y +${y}/4 - ${y}/100 - 32045"|bc)
jdn=$(echo "$jdn + 1"|bc|sed "s/...$//")
d=1
p=$(echo "29.530588853")
while [ "$d" != "32" ]
do
echo -n "$d"
days=$(echo "scale=2;${jdn} % ${p}"|bc)
fase=$(echo "scale=2;$p / $days"|bc)
fase1=$(echo "${fase}<7.382647213"|bc)
if [ $fase1 -eq 1 ]
then
echo -n "#"
elif [ $(echo "${fase}<14.76529443"|bc) -eq 1 ]
then
echo -n ")"
elif [ $(echo "$fase<22.14794164"|bc) -eq 1 ]
then
echo -n "0"
else
echo -n "("
fi
d=$(echo "$d + 1"|bc)
jdn=$(echo "$jdn +1"|bc)
done
jdn has as result 2455369, days should be 9.55 but the result is 0.054...
Arithmetic in Bash shell is done with integers only, so it is better to change the approach (or multiply the qantities by a large power of ten to make them be integers).
When you are doing math with integers in Bash, include the arithmetic in double parentheses, or to use a 'let' keyword.
((${jdn} % ${p}))
as described in these sources.
http://ubuntuforums.org/showthread.php?t=1970559
How to use mod operator in bash?
I've found a solution: without scale, it works fine. So this is my code:
days=$(echo "${jdn} % ${p}"|bc)
I only had to make sure that the modulo did'nt give a 0 back and than i could set scale in the division. It seemed to be more a math question at the end...
so I'm dealing with column averaging problems
I have several columns of number,
1 2 3 4 5
2 3 4 5 6
8 4 5 6 7
9 8 7 6 5
1 9 9 9 2
What I want to do is to take an average of each column so that they will yield
4 5 5 6 5
The summing part is not a problem, I'm able to get the sum of each column. However, somehow I'm having trouble in counting the number of columns (variable $x)
Here is my code
while read line; do
x = 0
read -a array <<< "$line"
for i in "${!array[#]}"
do
column[${i}]=$((${column[${i}]}+${array[$i]}))
((x++))
done
done < $TMP
for sum in ${column[#]}
do
average=`expr $sum / $x`
remainder=`expr $sum % $x`
mult=`expr $remainder \* 10`
fracvalue=`expr $mult / $x`
echo $x
echo $average
echo $sum
echo $remainder
echo $mult
echo $fracvalue
done
The last several lines are for my testing purposes, here the $X keeps showing 1 instead of 5. That's why it screws up all the other variable. Does anybody know where's the flaw in this code? Really appreciate your help. Thanks
Another approach:
#!/bin/bash
declare -ia sum # declare array of integers
declare -i lines=0 # declare integer to count lines
# read file to array and sum values
while read -ra array; do
for ((i=0; i<${#array[#]};i++)); do
sum[$i]+=${array[$i]}
done
lines+=1
done < file
# print averages
for ((j=0; j<$i;j++)); do
echo -n "$((${sum[$j]}/$lines)) "
done
Output:
4 5 5 6 5
The problem is in the line
x = 0
should be
x=0 and make ((x+1)) as let "x+=1" it should work.
Maybe your file doesn't have the same number of lines in each column.
while read line; do
read -a array <<< "$line"
for i in "${!array[#]}"
do
column[${i}]=$((${column[${i}]}+${array[$i]}))
((x[${i}]++))
done
done < $TMP
for i in ${!column[#]}
do
sum=${column[$i]}
x=${x[${i}]}
#your calcul
done
The initial issue, aside from a few syntax peculiarities, was the resetting of x on each read which caused you to lose your line count. Additionally, your array is an indexed array, not an associative array.
Making the small adjustments and declareing the variables at the beginning (to hint to bash they are integers or arrays), it works as planned. note: there is no need for a here-string to assign the array, just use regular array syntax. Also note, for indexed arrays, there is no need to dereference the variable within [ ], simply ${array[i]} is fine.
While the use of expr is fine (old, slow, but portable and fine), you could use bash arithmetic syntax for your parameter calculations at the end. (you already have arrays). Finally, you are better served initializing each column[$i]=0 on the first read loop. You can do that with a simple flag:
#!/bin/bash
declare -i ncols=0
declare -i x=0
declare -a column
while read -r line; do
array=( $line )
[ $ncols -eq 0 ] && ncols=${#array[#]}
for ((i = 0; i < ncols; i++))
do
[ $x -eq 0 ] && column[$i]=0
column[$i]=$(( ${column[i]} + ${array[i]}))
done
((x++))
done < "$1"
for sum in ${column[#]}
do
average=`expr $sum / $x`
remainder=`expr $sum % $x`
mult=`expr $remainder \* 10`
fracvalue=`expr $mult / $x`
echo $x
echo $average
echo $sum
echo $remainder
echo $mult
echo $fracvalue
done
exit 0
Output
$ bash colavg.sh dat/colavg.txt
5
4
21
1
10
2
5
5
26
1
10
2
5
5
28
3
30
6
5
6
30
0
0
0
5
5
25
0
0
0
This question already has answers here:
Recursive Fibonacci in Bash script
(5 answers)
Closed 8 years ago.
I was perusing the sight for some help with my code and came across a thread from about 4 months ago, however the user's final revision doesn't work when posted into bash, and produces some strange results. Here is my version, which also produces some strange results:
#!/bin/bash
fib()
{
ind=$1
if (( ind <= 0 ))
then echo 0
elif (( ind = 1 ))
then echo 1
else
echo $(( $(fib $((ind - 1)) ) + $(fib $((ind - 2)) ) ))
fi
}
echo fibbonacci sequence number $1 is $(fib $1)
so this block of code will end up always outputting 1. ./fib.sh 5 outputs
fibbonacci sequence number 5 is 1
so I tried to write the code a little closer to what the previous asker had,
#!/bin/bash
fib()
{
ind=$1
if (( ind <= 0 ))
then echo 1
else
echo $(( $(fib $((ind - 1)) ) + $(fib $((ind - 2)) ) ))
fi
}
echo fibbonacci sequence number $1 is $(fib $1)
While I don't understand the logic here, it actually starts to output fibonacci numbers,
but now I get a slightly different problem; ./fib.sh 3 outputs:
fibbonacci sequence number 3 is 5
./fib.sh 5 outputs :
fibbonacci sequence number 5 is 13
Well we know that the 3rd fibonacci number is 1, and the 5th is 3 so what gives? The code seems to skip ahead several fibonacci numbers, and I can't figure out what is logically wrong with my code.
Usually when writing Fibonacci sequence logic you have to special-case the first two numbers. That's what the first user has done: special-casing 0 and 1.
You've removed one instance of special-casing and shifted everything by one index, which explains one shift. The other is easy: the code is zero-indexed. That's why everything is "off by two".
What's wrong with the original code? This line:
elif ((ind = 1))
sets ind to 1. Otherwise it's fine.
A simple fix to your code is to replace this line:
if (( ind <= 0 ))
with
if (( ind <= 2 ))
and off you go. That gives you the one-indexed behavior you'd expect:
cternus#astarael ~/foo> for i in `seq 1 10`; do ./foo.sh $i; done
fibbonacci sequence number 1 is 1
fibbonacci sequence number 2 is 1
fibbonacci sequence number 3 is 2
fibbonacci sequence number 4 is 3
fibbonacci sequence number 5 is 5
fibbonacci sequence number 6 is 8
fibbonacci sequence number 7 is 13
fibbonacci sequence number 8 is 21
fibbonacci sequence number 9 is 34
fibbonacci sequence number 10 is 55
#!/bin/bash
function fib(){
if [ $1 -le 0 ]; then
echo 0
elif [ $1 -eq 1 ]; then
echo 1
else
echo $[`fib $[$1-2]` + `fib $[$1 - 1]` ]
fi
}
fib $1
#!/bin/bash
#fibonacci sequence function
fib()
{
ind=$1
if (( ind <= 0 ))
then echo 0
elif (( ind == 2 ))
then echo 1
else
echo $(( $(fib $((ind - 1)) ) + $(fib $((ind - 2)) ) ))
fi
}
echo fibbonacci sequence number $1 is $(fib $1)
So my problem was with the equality check in
elif (( ind = 1 ))
I should have used the double =, and change the 1 to a 2, so it should have been
elif (( ind == 2 ))
Ultimately my correct script should look like this
#!/bin/bash
#fibonacci sequence function
fib()
{
ind=$1
if (( ind <= 1 ))
then echo 0
elif (( ind == 2 ))
then echo 1
else
echo $(( $(fib $((ind - 1)) ) + $(fib $((ind - 2)) ) ))
fi
}
echo fibbonacci sequence number $1 is $(fib $1)
Thanks a bajillion and one to Christian Ternus for the help, I've been programming for a few years now and totally should have seen the equality check error >.<
Interestingly enough, the Korn shell executes #christianternus' script much faster than other shells:
$ for a in sh bash zsh ksh; do echo "shell: $a"; time for i in $(seq 1 20); do $a bin/fib.sh $i; done | md5sum; done
shell: sh
5fece53a38f2df040bfaf9632c2b7f4b -
real 0m29.508s
user 0m3.788s
sys 0m11.785s
shell: bash
5fece53a38f2df040bfaf9632c2b7f4b -
real 0m29.906s
user 0m3.604s
sys 0m11.235s
shell: zsh
5fece53a38f2df040bfaf9632c2b7f4b -
real 0m29.203s
user 0m2.505s
sys 0m14.377s
shell: ksh
5fece53a38f2df040bfaf9632c2b7f4b -
real 0m0.942s
user 0m0.843s
sys 0m0.079s