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
Related
I am facing an issue using if elif in bash ,my program is written below,i am careful about the spaces
#!/usr/bin/bash
echo "enter a number"
read num
if (( num >= 1 )) && (( num < 10 )); then
echo "sam"
elif (( num >= 10 )) && (( num < 90 )); then
echo "ram"
elif (( num >= 90 )) && (( num < 100 )); then
echo "rahim"
else
echo "tara"
fi
output:
sourav#LAPTOP-HDM6QEG8:~$ bash ifelse2.sh
enter a number
5
sam
sourav#LAPTOP-HDM6QEG8:~$ bash ifelse2.sh
enter a number
15
ram
sourav#LAPTOP-HDM6QEG8:~$ bash ifelse2.sh
enter a number
95
rahim
sourav#LAPTOP-HDM6QEG8:~$ bash ifelse2.sh
enter a number
105
ifelse2.sh: line 11: echo tara: command not found
So every if and elif works except for the else part,I am extra careful about spaces ,however still I am getting an error ,can someone help,thanks in advance
To fix the spotted problem:
perl -i -pe 's/\becho\b\W+\btara\b/echo tara/' ifelse2.sh
For arithmetic, a better way to code
(( num >= 1 )) && (( num < 10 ))
is
(( num >= 1 && num < 10 ))
And please, indent your code properly, especially when asking help to others.
The variable D is supposed to contain a positive integer. My FizzBuzz program has to use arithmetic substitution and the ||, &&, () operators. If the number is a multiple of three, the program should output the word Fizz; if the number is a multiple of five, the word Buzz. If the number is a multiple of three and five, then the program should display the word FizzBuzz. I am a novice programmer, unsure where I have gone wrong.
"""
#!/bin/bash
D=5
if [ $D % 3 == 0 ] ;
then
echo "Fizz"
elif [[ $D % 5 == 0 ]]
then
echo "Buzz"
elif [[ $D % 3 == 0 && $D % 5 == 0 ]]
fi
echo "FizzBuzz"
done
"""
To perform computations I recommend (( and )):
#!/bin/bash
d=5
if (( $d%3 == 0 && $d%5 == 0 )); then
echo "FizzBuzz";
else
if (( $d%3 == 0 )); then
echo "Fizz"
elif (( $d%5 == 0 )); then
echo "Buzz"
fi
fi
I'm having a bit of trouble, id like to store the contents of the values from my for loop into an array or something and then recall these values to be tested against the if statements and then printed accordingly. My current code gives me a good output however if I use large numbers like 1 and 50 as input values it gives me multiple rows of "Divisible by xValue" instead of just one of each value. Thanks in advance
if (( $# > 2 )); then
echo "Only your first two values will be used"
for((i=($1+($1%2));i<($2-3);i+=2));do #for loop lists all even numbers between two input values
if (( i % 7 == 0 )); then #checks if even number divisible by 7
echo " $i : Divisible by 7 " # prints number and labels
elif (( $i % 11 == 0 )); then #else if checks if divisible by 7
echo " $i : Divisible by 11 " #prints number and labels
elif (( $i % 13 == 0 )); then #if divisible by 13
echo " $i : Divisible by 13 "
fi #closes the if statement
printf "%d%s, " "$i"
done
echo "$i"
Use +=() in bash to add a new element into an array.
#! /bin/bash
set -eu
if (( $# > 2 )); then
echo "Only your first two values will be used"
fi
even=()
for ((i=$1; i<=$2; ++i)) ; do
if (( i % 2 == 0 )) ; then
even+=($i)
fi
done
for e in "${even[#]}" ; do
for d in 7 11 13 ; do
if (( e % d == 0 )); then
echo "$e: Divisible by $d"
break
fi
done
printf "%d%s, " "$e"
done
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 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