Recursive Fibonacci in Bash script - bash

This is my attempt:
#!/bin/bash
function fibonacci(){
first=$1
second=$2
if (( first <= second ))
then
return 1
else
return $(fibonacci $((first-1)) ) + $(fibonacci $((second-2)) )
fi
}
echo $(fibonacci 2 0)
I think i'm having trouble with the else statement. I get the error return: +: numeric argument required
on line 14.
The other problem that i'm having is that the script doesn't display any numbers even if i do echo $(fibonacci 0 2). I thought it would display a 1 since i'm returning a 1 in that case. Can someone give me a couple of tips on how to accomplish this?
After checking out some of your answers this is my second attempt.. It works correctly except that it displays the nth fibonacci number in the form 1+1+1+1 etc. Any ideas why?
#!/bin/bash
function fibonacci(){
first=$1
second=$2
if (( first <= second ))
then
echo 1
else
echo $(fibonacci $((first-1)) ) + $(fibonacci $((first-2)) )
fi
}
val=$(fibonacci 3 0)
echo $val
My final attempt:
#!/bin/bash
function fibonacci(){
first=$1
if (( first <= 0 ))
then
echo 1
else
echo $(( $(fibonacci $((first-1)) ) + $(fibonacci $((first-2)) ) ))
fi
}
val=$(fibonacci 5)
echo $val
thanks dudes.

#!/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

The $(...) substitution operator is replaced with the output of the command. Your function doesn't produce any output, so $(...) is the empty string.
Return values of a function go into $? just like exit codes of an external command.
So you need to either produce some output (make the function echo its result instead of returning it) or use $? after each call to get the value. I'd pick the echo.

As Wumpus said you need to produce output using for example echo.
However you also need to fix the recursive invocation.
The outermost operation would be an addition, that is you want:
echo $(( a + b ))
Both a and b are substitutions of fibonacci, so
echo $(( $(fibonacci x) + $(fibonacci y) ))
x and y are in turn arithmetic expressions, so each needs its own $(( )), giving:
echo $(( $(fibonacci $((first-1)) ) + $(fibonacci $((second-2)) ) ))
If you are confused by this, you should put the components into temporary variables and break down the expression into parts.
As to the actual fibonacci, it's not clear why you are passing 2 arguments.

Short version, recursive
fib(){(($1<2))&&echo $1||echo $(($(fib $(($1-1)))+$(fib $(($1-2)))));}

While calculating fibonacci numbers with recursion is certainly possible, it has a terrible performance. A real bad example of the use of recursion: For every (sub) fibonacci number, two more fibonacci numbers must be calculated.
A much faster, and simple approach uses iteration, as can be found here:
https://stackoverflow.com/a/56136909/1516636

Related

Why does this bash script work even with the typo

So I have this bash script to find the Fibonacci sequence for n terms. Its definitely not great code, but I notices that it still works with a typo
read -p "Enter which term of fibo seq to find: " n
table=(1 1)
for i in $(seq 0 $(($n - 1)) )
do
if [[ -z ${table[$i]} ]]; then
a1=$(( $i - 1 ))
a2=$(( $I - 2 ))
val=$(( ${table[$a1]} + ${table[$a2]} ))
table+=($val)
fi
done
echo ${table[#]}
inside the if statement evaluating the expression for a2, there is a capital 'I' instead of 'i'. My understanding is that shellscript is case sensitive but I'm new to it. So can anyone explain why this works?
a2 will always be -2. Starting with bash 4.2, you can index into an array using negative indices, much like in Python. So with or without the typo, you are always accessing the second last element in the array.
The statement a2=$(( $I - 2 )) where $I is not declared is equal to a2=$(( - 2 )) which means a2 will always be equal to -2.

Recursion in bash(fibonacci sequence)

The main problem my code doesn't do echo every time(fibonacci sequence)
#!/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
i was expecting it will do echo every time. It shows:
~/Bash$ ./fn.sh 12
144
but i need it to show like this:
~/Bash$ ./fn.sh 12
0
1
1
2
3
5
8
13
21
34
55
89
144
Your function is consuming the output of its invocation via backticks (command substitution). Only the last output is sent to the terminal. Your function will only return the n-th number of the Fibonacci sequence.
If you want to return all the numbers of the sequence up to a certain point, you can use a loop:
for i in $(seq "$i"); do
fib "$i"
done
Another method might be:
#!/bin/bash
fibseq () {
echo "$1"
if (($3 > 0)); then fibseq "$2" $(($1 + $2)) $(($3 - 1)); fi
}
if (($1 > 0)); then fibseq 0 1 "$1"; fi
Note that this is just a loop disguised as recursion. This method is much more efficient than the naive recursive version to compute Fibonacci sequences. Arguments to fibseq function: $3 serves as a counter, $1 and $2 are the last two Fibonacci numbers.
As an aside note, you can replace the $(($1 + $2)) with $(bc <<< "$1 + $2") if you want arbitrary-precision arithmetic.
Finally, don't use the $[…] form for arithmetic expansion. Use $((…)) instead.

Subtraction and addition variables in bash script [duplicate]

for i in {1..99}
do
if ([ $((i % 2)) -eq 1 ])
then
echo $i
fi
done
I'm learning bash, and I'm trying to better understand line 3. Why does $((i % 2)) have to be double wrapped in parenthesis, and why can't I put the $ symbole inside next to the i like:
([ (($i % 2)) -eq 1 ])
or
([ ($(i % 2)) -eq 1 ])
?
Everything inside $((...)) is treated as an arithmetic expression. You can use parameter expansion inside an arithmetic expression, but a bare string is interpreted as a variable whose (integer) value is used. You can write
if [ $(( i % 2 )) -eq 1 ]
to check if i is odd. You can also check for equality inside the expression, as $(( x == y )) evaluates to 1 if x == y and 0 otherwise, but you would still have to compare that value to something.
In bash, you can use the arithmetic command, which has an exit status of 0 if the resulting value is non-zero, and 1 otherwise. This lets you write
if (( i % 2 == 1 )); then
$(( expression )) is the syntax for evaluating an arithmetic expression, and replacing this syntax with the result of that expression. It's documented in the Bash Manual here;
The syntax of arithmetic expressions is described here. Putting $ before variable names is optional, so you can also write it as $(($i % 2)).
You have to wrap it in two parentheses because $(...) already has a meaning, it's used for command substitution: $(some command) executes some command and is then replaced with the output of the command.
You don't need parentheses around [ ... ]. The normal way to write your if statement would be
if [ $((i % 2)) -eq 1 ]
You can also write it as
if (( i % 2 == 1 ))
(( expression )) evaluatees the arithmetic expression, and then sets its exit status depending on whether the result is zero or non-zero.
Since you specify bash, simplest is
for i in {1..99}
do if ((i % 2))
then echo $i
fi
done
the ((i % 2)) will return i mod 2, which will always be zero or one. This particular construct behaves like a C-style boolean, so zero is false and anything else is true (the opposite behavior from [[ ... ]] which uses return code of zero to mean true/ok).
You can also use expr:
for i in {1..99}
do
num=`expr i % 2`
if (( num == 1 ))
then
echo $i
fi
done

Could you explain the syntax of math in a bash shell?

for i in {1..99}
do
if ([ $((i % 2)) -eq 1 ])
then
echo $i
fi
done
I'm learning bash, and I'm trying to better understand line 3. Why does $((i % 2)) have to be double wrapped in parenthesis, and why can't I put the $ symbole inside next to the i like:
([ (($i % 2)) -eq 1 ])
or
([ ($(i % 2)) -eq 1 ])
?
Everything inside $((...)) is treated as an arithmetic expression. You can use parameter expansion inside an arithmetic expression, but a bare string is interpreted as a variable whose (integer) value is used. You can write
if [ $(( i % 2 )) -eq 1 ]
to check if i is odd. You can also check for equality inside the expression, as $(( x == y )) evaluates to 1 if x == y and 0 otherwise, but you would still have to compare that value to something.
In bash, you can use the arithmetic command, which has an exit status of 0 if the resulting value is non-zero, and 1 otherwise. This lets you write
if (( i % 2 == 1 )); then
$(( expression )) is the syntax for evaluating an arithmetic expression, and replacing this syntax with the result of that expression. It's documented in the Bash Manual here;
The syntax of arithmetic expressions is described here. Putting $ before variable names is optional, so you can also write it as $(($i % 2)).
You have to wrap it in two parentheses because $(...) already has a meaning, it's used for command substitution: $(some command) executes some command and is then replaced with the output of the command.
You don't need parentheses around [ ... ]. The normal way to write your if statement would be
if [ $((i % 2)) -eq 1 ]
You can also write it as
if (( i % 2 == 1 ))
(( expression )) evaluatees the arithmetic expression, and then sets its exit status depending on whether the result is zero or non-zero.
Since you specify bash, simplest is
for i in {1..99}
do if ((i % 2))
then echo $i
fi
done
the ((i % 2)) will return i mod 2, which will always be zero or one. This particular construct behaves like a C-style boolean, so zero is false and anything else is true (the opposite behavior from [[ ... ]] which uses return code of zero to mean true/ok).
You can also use expr:
for i in {1..99}
do
num=`expr i % 2`
if (( num == 1 ))
then
echo $i
fi
done

How to learn if a value is even or odd in bash?

I am building a movie database and I need to find a median for ratings.
I'm really new to bash (it's my first assignment).
I wrote:
let evencheck=$"(($Amount_of_movies-$Amount_of_0_movies)%2)"
if [ $evencheck==0 ]
then
let median="(($Amount_of_movies-$Amount_of_0_movies)/2)"
else
let median="(($Amount_of_movies-$Amount_of_0_movies)/2)+1"
fi
When $amount_of_movies = 6 and $amount_of_0_movies = 1. I would expect median to be 3. but it's 2. Why is that?
#!/bin/bash
if (( $# != 1 )) ; then
echo "syntax: `basename $0` number"
exit 255
else
_value=$(expr $1 % 2)
(( $_value == 0 )) && exit 1 || exit 0
fi
try this:
let evencheck="(($Amount_of_movies-$Amount_of_0_movies)%2)"
if [ $evencheck -eq 0 ]
then
let median="(($Amount_of_movies-$Amount_of_0_movies)/2)"
else
let median="(($Amount_of_movies-$Amount_of_0_movies)/2)+1"
fi
Removing the $, and then testing for numeric equality.
try this in your if test:
[ "$evencheck" == 0 ]
Does median have some sort of default value? The way I see it, it's not even going inside the if.
(6-1) % 2
5 % 2
1, not 0
Your code doesn't parse. To evaluate expressions in Bash, you say
let evencheck="$((($Amount_of_movies-$Amount_of_0_movies)%2))"
That is, evaluate arithmetics like so: $(( ... ))
That said, your problem is in the conditional. See man test.
if [ $evencheck = 0 ]; then
You have to wrap the equality sign with whitespace on both sides. Use a single equality sign.
The outermost parentheses and none of the quotes are necessary in what you've got (they may be in other circumstances). Also, in a let statement you can omit the dollar sign from variable names.
let evencheck=(Amount_of_movies-Amount_of_0_movies)%2
if [ $evencheck == 0 ]
then
let median=(Amount_of_movies-Amount_of_0_movies)/2
else
let median=(Amount_of_movies-Amount_of_0_movies)/2+1
fi
If you use the (()) form instead of let, you can uses spaces to make your formulas more readable. You can also use them in if statements:
(( evencheck = ( Amount_of_movies - Amount_of_0_movies ) % 2 ))
if (( evencheck == 0 ))
then
(( median = ( Amount_of_movies - Amount_of_0_movies ) / 2 ))
else
(( median = ( Amount_of_movies - Amount_of_0_movies ) / 2 + 1 ))
fi

Resources