Linux bash脚本,递归求和数字

5

我希望你能帮助我理解在Bash脚本中递归是如何工作的。

我想把数字作为参数插入:

sh script.sh 4

结果应该是(1+2+3+4)=10。

这是我写的,我的想法很好,但无法使其正常工作。

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

我认为我想得对,但也许我错了。

这可能会有所帮助:https://dev59.com/aGkw5IYBdhLWcg3wu9Fg - adurian
expr通常已被弃用--在现代POSIX派生shell中使用它没有任何理由。 $(( ))允许您在任何POSIX shell中进行数学运算,而(( ))则允许您在bash中进行相同的操作,而不会扩展结果。 - Charles Duffy
3个回答

6

不要使用全局变量:

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

注:

  • local 声明命名变量为此函数的本地变量 (参考)
  • sum=${2:-0} 将 "sum" 变量定义为第二个参数,如果第二个参数为空或未设置,则定义为0 (参考)
  • $FUNCNAME 当前运行函数的名称 (参考)。这是递归调用,将 "n-1" 和 "sum+n" 作为参数传递。

+1。话说,建议多加引号以更好地展示良好的编程实践。(尽管对于数字值来说它们不如其他情况那么必要,但如果有人将“1 23”作为数字传递进来,最好以这种方式检测并失败并返回适当的错误信息)。 - Charles Duffy
谢谢你的帮助。但是我就是无法让这段代码工作。在终端中,我得到了这个错误 - script.sh 11: script.sh n: not found, script.sh 15: script.sh: 4: not found。由于我对脚本不熟悉,所以我不知道这意味着什么。 - user3127680
你正在像这样调用脚本 sh script.sh 5,这是一个问题:这是一个 bash 脚本,所以你需要使用 bash 解释器运行它:bash script.sh 5。或者,给它执行权限并像程序一样运行它:chmod u+x script.sh; ./script.sh 5 - glenn jackman
谢谢您解释如何运行它。您能否稍微解释一下代码的作用? 我想知道这个是做什么的 - local sum=${2:-0} 以及这个是做什么的 - $FUNCNAME $((n - 1)) $((sum + n)) - user3127680

2
这可以实现为一个shell函数:
rec() { [ "$1" -gt 0 ] && echo $(( $1 + $( rec $(($1-1)) ) )) || echo 0 ; }

以下是样例结果,展示了在命令行中定义rec并在多个情况下运行的情况:

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

工作原理:函数rec接受一个整数参数。它首先使用test检查该参数是否大于零:[ "$1" -gt 0 ]。如果大于零,则将参数添加到rec $(($1-1))的结果中。如果参数为零,则只返回(回显)零。

使用if/then/else实现:有些人可能会发现,如果将&&/||逻辑替换为if语句,则更清晰:

rec() {
    if [ "$1" -gt 0 ]
    then
        echo $(( $1 + $( rec $(($1-1)) ) ))
    else
        echo 0
    fi
}

0
您可以使用这个递归函数:
recuradd() {
    n=$1
    [[ $n -eq 0 ]] && return
    (( res += n-- ))
    recuradd $n
}

然后使用以下方式调用:

res=0; recuradd 4; echo $res
10

res=0; recuradd 5; echo $res
15

3
这是一个伪装成尾递归的循环。它不使用局部变量,实际上依赖于变量 rec 被重复使用。不算好也不算坏,但有风险。 - Henk Langeveld

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接