I have written a short Bash Script:
for j in 0 1 2 3 4 5
do
for (( i=$j; i <= 5; i++ ));
do
if [ $(($(($i - $j)) > 1)) ]; then
echo "True"
else
echo "False"
fi
done
done
I expect this script to output a mixture of Trues and Falses however it only outputs Trues. I have checked and seen that $(($(($i - $j)) > 1)) is correctly producing 0s and 1s as it is supposed to but apparently the if statement is not registering these and always assumes "True".
Am I missing something in my code?
Thank you very much
James
Your script is checking if [ 0 ] and if [ 1 ] which isn't what you think. It will always return true because it is checking that the length of the string 0 and 1 is not zero.
Change it to:
for j in {0..5}
do
for (( i=j; i<=5; i++ ))
do
if (( i - j > 1 ))
then
echo True
else
echo False
fi
done
done
Note that the use of the $ prefix for variables within ((...)) is optional.
You're using if incorrectly, you're testing for string length when you want an arithmetic comparison:
for j in {0..5}; do
for i in $(seq $j 5); do
if (( i - j > 1 )); then
echo "True"
else
echo "False"
fi
done
done
Related
I'd like to know how to print Fibonacci series using recursion in bash with only 1 variable.
From what I've done:
fib()
{
i=$1
if (( $i <= 1 ))
then echo 0
elif (( $i == 2 ))
then echo 1
else
echo $(( $(fib $(($i - 1)) ) + $(fib $(($i - 2)) ) ))
fi
}
echo $(fib $1)
I get the correct output of the final iteration, for example if I enter 10 I will get 34, but I'd like to print the whole sequence of numbers, i.e. all the iterations as well. How can I achieve that?
Another way I tried was by:
#!/bin/bash
arr[0]=0
arr[1]=1
for (( i=0; i<=10; i++ ))
do
echo -n "${arr[0]} "
arr[0]=$((${arr[0]} + ${arr[1]} ))
arr[1]=$((${arr[0]} - ${arr[1]} ))
done
echo ""
But obviously here I've used a for loop, but I don't want to use another variable.
Just for (my kind of) fun, this code prints the Fibonacci numbers from the 0th to the 92nd (as defined in Fibonacci number - Wikipedia) with a recursive function that uses no variables:
#! /bin/bash
function fib
{
echo ${3-0}
(($1 > 0)) && fib $(($1-1)) ${3-0} $((${2-1}+${3-0}))
}
fib 92
Some may claim that using the positional parameters ($1, $2, $3) for this is cheating, but then other solutions could be said to be using two variables ($i and $1).
The code takes under 0.01 seconds to run on my (oldish) Linux machine.
The code should work with numbers up to 92 with Bash version 3 or later on any platform. See Bash Number Limit?. Numbers higher than 93 will cause to code to produce garbage results due to arithmetic overflow.
Variables in bash are global by default. You need to make i local explicitly.
fib () {
local i
i=$1
if (( i <= 1 )); then
echo $i
else
echo $(( $(fib $((i-1)) ) + $(fib $((i - 2)) ) ))
fi
}
(Also, your base cases are a little off if you are starting with 0, and 2 need not be a base case; fib 2 can be derived from the base cases fib 0 and fib 1.)
If you want to print each fibonacci value from 1 to $n, I suggest:
fib_r() {
local i=$1
if (( i < 0 )); then
echo "Error: negative numbers not allowed" >&2
exit 1
elif (( i <= 1 )); then
echo $i
else
echo $(( $($FUNCNAME $((i - 1)) ) + $($FUNCNAME $((i - 2)) ) ))
fi
}
fib() {
local i
for (( i = 1; i <= $1; i++ )); do
fib_r $i
done
}
fib 10
outputs
0
1
1
2
3
5
8
13
21
34
It's still one variable, albeit one per function.
I use the bash variable $FUNCNAME in the recursive function so you don't have to hardcode the function name within itself. I got bit by not updating that line when I renamed the function.
Of course your performance will greatly improve if you cache the results: "fib 16" takes, on my VM, about 3.5 sec without caching and about 0.03 sec with caching.
fib_r() {
local i=$1
if (( i < 0 )); then
echo "Error: negative numbers not allowed" >&2
exit 1
elif [[ -n ${fib_cache[i]} ]]; then
echo "${fib_cache[i]}"
elif (( i <= 1 )); then
echo $i
else
echo $(( $( $FUNCNAME $((i - 1)) ) + $( $FUNCNAME $((i - 2)) ) ))
fi
}
fib_cache=()
fib() {
local i
for ((i=1; i<=$1; i++)); do
fib_cache[i]=$(fib_r $i)
echo "${fib_cache[i]}"
done
}
I just found the following FizzBuzz example on Hacker News and it uses a piece of syntax I'm finding it difficult to search for
for num in {1..100} ; do
out=""
(( $num % 3 == 0 )) && out="Fizz"
(( $num % 5 == 0 )) && out="${out}Buzz"
echo ${out:-$num}
done
The bit I don't understand is how the variable usage works in the echo line. Though I can obviously see that it becomes $out if not empty, else $num
for num in {1..100} ; do
Loop from 1 to 100.Set num to each integer on the way
out=""
Set out to nothing
(( $num % 3 == 0 )) && out="Fizz"
If the number is divisible by 3 set out to Fizz
(( $num % 5 == 0 )) && out="${out}Buzz"
If the number is divisible by 5 set out to whatever is contained in out then Buzz.
echo ${out:-$num}
Uses parameter substitution to check that out contains something, if it does not, then use num instead.
Echos result of the substitution.
done
Resources
http://tldp.org/LDP/abs/html/parameter-substitution.html - parameter substitution
http://tldp.org/LDP/abs/html/ops.html - let command ((...))
http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-7.html - loops
I tried to do a for loop with 2 conditions but I didn't succeed in any way:
for (( i=0 ; -e /file && i < 10 ; i++ ))
of course I tried any combination of parentheses like:
for (( i=0 ; [ -e /file ] && [ i < 10 ] ; i++ ))
for (( i=0 ; [ -e /file -a i < 10 ] ; i++ ))
What's wrong on this?
I googled a lot for this, but I didn't find any suggestion.
You have to do some subshell trickery to pull this off:
for (( i=0 ; $([ -e /file -a $i -lt 10 ]; echo "$?") == 0; i++ ))
Or probably better:
for (( i=0 ; $([ -e /file ]; echo "$?") == 0 && i < 10; i++ ))
What's happening here is that $(...) is being run and placed into the mathematical expression ... == 0. When it's run the echo "$?" spits out the return code for [ which is 0 for no-error (i.e. expression is true), and 1 for error (i.e. expression is false) which then gets inserted as 0 == 0 or 1 == 0.
I was trying a sample program, to check the odd and even no's and was getting an error as below,
#!/bin/bash
N=10
for i in 1..N
if [$i/2 == 0]
then
echo "even"
else
echo "Odd"
fi
Error:
./case.sh: line 5: syntax error near unexpected token `if'
./case.sh: line 5: `if [$i/2 == 0]'
EDITED :
#!/bin/bash
N=10
for i in 1..N
do
if(( ($i/2) == 0 ));
then
echo "even"
else
echo "Odd"
fi
done
error :
./case.sh: line 6: ((: (1..N/2) == 0 : syntax error: invalid arithmetic operator (error token is "..N/2) == 0 ")
Odd
Correct working code :
#!/bin/bash
N=3
for (( i=1; i <= N; i++ ));
#for i in 1..N; // This didnt work
do
if [[ $i/2 -eq 0 ]]
#if (( i/2 == 0 )); // This also worked
then
echo "even"
else
echo "Odd"
fi
done
[ ] or [[ ]] needs spaces between its arguments. And in your case you should use [[ ]] or (( )) as [ ] can't handle division along with comparison:
if [[ 'i / 2' -eq 0 ]]; then
if (( (i / 2) == 0 )); then
for i in 1..N; do should also be
for (( i = 1; i <= N; ++i )); do
You probably meant to have a form of brace expansion, but you can't apply a parameter name on it:
{1..10} ## This will work.
{1..N} ## This will not work.
Using eval may fix it but better go for the other form of for loop instead.
Try this :
#!/bin/bash
N=10
for i in $(seq 1 $N); do
if [ `expr $i % 2` -eq 0 ]
then
echo "even"
else
echo "Odd"
fi
done
1..N is not a valid syntax in bash(though I think you might be coming from ruby background), you can use seq.
In bash script, below while loop is supposed to print 1 to 4 number.
But this one is resulting as an infinite loop.
COUNT=1
while [ $COUNT < 5 ];
do
echo $COUNT
COUNT=$(($COUNT+1))
done
Is there any fault in condition or syntax ? (I think so...)
Use -lt instead of <:
COUNT=1; while [ $COUNT -lt 5 ]; do echo $COUNT; COUNT=$(($COUNT+1)); done
1
2
3
4
BASH syntax with [ doesn't recognize >, <, <=, >= etc operators. Check man test.
Even better is to use arithmetic processing in (( and )):
COUNT=1; while (( COUNT < 5 )); do echo $COUNT; ((COUNT++)); done
OR using for loop:
for (( COUNT=1; COUNT<5; COUNT++ )); do echo $COUNT; done