bash中的递归函数

Fin*_*iny 30 bash recursion function

我想做一个函数,它将在bash中返回一个数字的阶乘

这是当前不起作用的代码,任何人都可以告诉我什么是错的以及如何纠正它?我刚开始学习bash,我不知道那么多.

#!/bash/bin
factorial()
{
  let n=$1
  if (( "$n" <= "1" ))
  then return 1
  else
  factorial n-1
  return $n*$?
  fi
  return 0
}
factorial 5
echo "factorial 5 = $?"
Run Code Online (Sandbox Code Playgroud)

Dan*_*ina 36

有几种语法和一个非常明显的逻辑(返回0)

下面是一个工作版本:

#!/bin/bash

factorial()
{
    if [[ $1 -le 1 ]]
    then
        echo 1
    else
        last=$(factorial $[$1-1])
        echo $(($1 * last))
    fi
}
factorial 5
Run Code Online (Sandbox Code Playgroud)

你错过了:

  1. 如果语法不好

  2. 递归调用很糟糕

  3. 返回不好(eval语法坏了)

  4. shbang line(/ bin/bash not/bash/bin)

  • 返回代码是单个字节,因此对于n> 5会中断.要解决此问题,您需要更改函数以回显结果,而不是设置返回代码. (34认同)
  • +1和+9000到@tripleee.bash中的函数应该回显结果,而不是返回结果. (9认同)
  • `$ [...]`语法已经被弃用了几十年.停止使用它. (7认同)
  • @tripleee 一个字节是 8 位或 2^8 个数字。因此 bash `return` 范围是 `0-255` (2^8 - 1)。但我同意仍然应该避免 return 并用 echo 代替。 (2认同)

use*_*300 17

#!/bin/bash

function factorial() 
{ 
   if (( $1 < 2 ))
   then
     echo 1
   else
     echo $(( $1 * $(factorial $(( $1 - 1 ))) ))
   fi
}
Run Code Online (Sandbox Code Playgroud)

这会更好.

(无论如何,它最多可以工作25,这应该足以证明关于递归的观点.)

对于更高的数字,bc将是使用的工具,使上面的第九行:

echo "$1 * $(factorial $(( $1 - 1 )))" | bc
Run Code Online (Sandbox Code Playgroud)

但你必须对bc有点小心 -

$ factorial 260
38301958608361692351174979856044918752795567523090969601913008174806\
51475135399533485285838275429773913773383359294010103333339344249624\
06009974551133984962615380298039823284896547262282019684886083204957\
95233137023276627601257325925519566220247124751398891221069403193240\
41688318583612166708334763727216738353107304842707002261430265483385\
20637683911007815690066342722080690052836580858013635214371395680329\
58941156051513954932674117091883540235576934400000000000000000000000\
00000000000000000000000000000000000000000
Run Code Online (Sandbox Code Playgroud)

对我糟糕的系统来说是一种压力!

  • @TorosFanny你是对的,可以重写它以避免创建子shell - 这里有一个很好的答案:/sf/ask/2349763881/​​ls-when-递归调用函数感谢您的评论,它帮助我学习了新东西! (2认同)

koj*_*iro 5

echo-对结果进行运算可能是获得n> 5的结果的唯一方法,但是捕获回显结果需要一个子shell,这意味着递归将很快变得昂贵。较便宜的解决方案是使用变量:

factorial() {
    local -i val=${val:-($1)}
    if (( $1 <= 1 )); then
        echo $val
        return
    fi
    (( val *= $1 - 1 ))
    factorial $(( $1 - 1 ))
}
Run Code Online (Sandbox Code Playgroud)

如果要确保val启动时未设置该设置,请使用包装函数:

factorial() {
    local -i val=$1
    _fact() {
        if (( $1 <= 1 )); then
            echo $val
            return
        fi
        (( val *= $1 - 1 ))
        _fact $(( $1 - 1 ))
    }
    _fact $1
}
Run Code Online (Sandbox Code Playgroud)

为了比较:

# My Method
$ time for i in {0..100}; do factorial $(( RANDOM % 21 )); done > /dev/null 

real    0m0.028s
user    0m0.026s
sys     0m0.001s

# A capturing-expression solution
$ time for i in {0..100}; do factorial $(( RANDOM % 21 )); done > /dev/null 

real    0m0.652s
user    0m0.221s
sys     0m0.400s
Run Code Online (Sandbox Code Playgroud)

  • 合理的建议。尽管如此 - 如果您没有使用随机输入,您的测量结果会更有说服力。据我们所知,您的方法进行了 100 次阶乘 (1) 计数,而另一个进行了 100 次阶乘 (20) 计数:) (2认同)