5

I want to figure it out how recursion works in bash scripting.

I want to insert number as a parameter:

sh script.sh 4

And result would be (1+2+3+4)= 10

This is what I wrote and in my head works just fine, but can't make it work.

n=$1
j=1
result=0

recursion(){ 
    result=`expr $result + $j` 
    j=`expr $j + 1`

    if [ "$n" -gt 0 ]; then
        recursion      #is this how you do recursion?
        n=`expr $n - 1
    else
        echo $result 
    fi
}

recursion

I think I imagined right but probably I am wrong.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
user3127680
  • 353
  • 2
  • 4
  • 13
  • http://stackoverflow.com/questions/9682524/recursive-function-in-bash This may help – adurian Mar 17 '14 at 18:08
  • `expr` is generally deprecated -- there's no reason to use it in modern POSIX-derivative shells. `$(( ))` lets you do math in any POSIX shell, and `(( ))` lets you do the same without results being expanded in bash. – Charles Duffy Mar 17 '14 at 20:08

3 Answers3

6

Don't use global variables:

#!/bin/bash

add_recursively () {
    local n=$1
    local sum=${2:-0}
    if (( n == 0 )); then
        echo $sum
        return
    fi
    $FUNCNAME $((n - 1)) $((sum + n))
}

# input validation
if ! [[ $1 =~ ^[[:digit:]]+$ ]]; then
    echo "I need a non-negative integer, not $1"
    exit 1
fi

echo $(add_recursively $1)

Notes:

  • local declares the named variables to be local to this function (ref)
  • sum=${2:-0} defines the "sum" variable as the 2nd parameter, or 0 if the 2nd parameter is empty or unset (ref)
  • $FUNCNAME name of the currently running function (ref). This is the recursive call, passing "n-1" and "sum+n" as the parameters.
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
  • +1. That said, might suggest more quotes just to better demonstrate good practices. (Granted, they're less necessary for numeric values than in other cases, but if someone passes in `'1 23'` as a number, better to detect it that way and fail with an appropriate error). – Charles Duffy Mar 17 '14 at 20:09
  • Thank you for the help. But I just can't make this code work. I get this error in terminal - script.sh 11: script.sh n: not found, script.sh 15: script.sh: 4: not found I'm new to scripts so I don't know what this mean. – user3127680 Mar 17 '14 at 21:14
  • You are invoking the script like `sh script.sh 5`, that's a problem: this is a **bash** script, so you need to run it with a **bash** interpreter: `bash script.sh 5`. Or, give it execute permissions and run it like a program: `chmod u+x script.sh; ./script.sh 5` – glenn jackman Mar 17 '14 at 21:16
  • Thanks for explaining how to run it. Can you pleas explain a little bit what does code do? I want to know what this do - local sum=${2:-0} and what this do - $FUNCNAME $((n - 1)) $((sum + n)) – user3127680 Mar 17 '14 at 21:29
2

This can be implemented as a shell function:

rec() { [ "$1" -gt 0 ] && echo $(( $1 + $( rec $(($1-1)) ) )) || echo 0 ; }

Here are sample results showing rec being defined at the command line and then run for several cases:

$ rec() { [ "$1" -gt 0 ] && echo $(( $1 + $( rec $(($1-1)) ) )) || echo 0 ; }
$ rec 4
10
$ rec 5
15
$ rec 6
21

How it works: The function rec takes a single integer argument. It first checks if that argument is greater than zero. This is done using test: [ "$1" -gt 0 ]. If it is greater than zero, it adds the argument to the result of rec $(($1-1)). If the argument is zero, it just returns (echoes) zero.

Implemented using if/then/else: Some may find it more clear if the &&/|| logic is replaced with an if statement:

rec() {
    if [ "$1" -gt 0 ]
    then
        echo $(( $1 + $( rec $(($1-1)) ) ))
    else
        echo 0
    fi
}
John1024
  • 109,961
  • 14
  • 137
  • 171
0

You can use this recursive function:

recuradd() {
    n=$1
    [[ $n -eq 0 ]] && return
    (( res += n-- ))
    recuradd $n
}

Then call using:

res=0; recuradd 4; echo $res
10

res=0; recuradd 5; echo $res
15
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • 3
    This is a loop hiding as tail recursion. It doesn't use local variables, and actually depends on variable `rec` being reused. Not good, not bad, but risky. – Henk Langeveld Mar 17 '14 at 19:30