bash - 递归调用函数时如何阻止bash创建子shell

标签 bash shell recursion process

这是一个计算阶乘的简单 shell 函数。

#!/bin/bash

function factorial()
{
   if (( $1 < 2 ))
   then
     echo 1
   else
     echo $(( $1 * $(factorial $(( $1 - 1 ))) ))
   fi
}

factorial $1

但我发现当给定一个非常大的输入时,这个脚本会创建许多子 shell。这是没有必要的,而且效率不高。有没有什么方法可以在不创建新子 shell 的情况下调用递归函数?

我的目标不是如何在 shell 中编写阶乘函数,而是如何在调用递归定义的函数时避免创建子 shell。

事实上,即使是一个简单的函数调用也会导致子 shell 的创建:

#!/bin/bash

function fac0() {
  ps >> log
  echo $1
}

function fac1() {
  ps >> log
  echo $(( $1 * $(fac0 $(( $1 - 1 ))) ))
}

touch log
fac1 $1

运行脚本后,log 文件的内容是:(它仍然创建子 shell)

  PID TTY          TIME CMD
 9205 pts/8    00:00:00 bash
 9245 pts/8    00:00:00 call_subshell.s
 9247 pts/8    00:00:00 ps
  PID TTY          TIME CMD
 9205 pts/8    00:00:00 bash
 9245 pts/8    00:00:00 call_subshell.s
 9248 pts/8    00:00:00 call_subshell.s
 9249 pts/8    00:00:00 ps

由于创建了子 shell,因此存在其他不需要的方面。

#!/bin/bash

declare -i i
i=0

function factorial() {
   i=$(($i + 1))
   if (( $1 < 2 ))
   then
     echo 1
   else
     local c=$(( $1 - 1 ))
     echo $(( $1 * $(factorial $c) ))
   fi
}

factorial $1
echo $i

无论参数是多少,这个脚本都会打印$i=1!

最佳答案

避免递归:

#!/bin/bash
factorial() {
    local f=1
    for ((i=2; i<=$1; i++)) ; do
        (( f *= i ))
    done
    echo $f
}

factorial $1

子 shell 是由于命令替换而产生的。使用“参数作为结果”的方式来避免它:

#!/bin/bash

# set -xv

factorial() {
    # echo $BASH_SUBSHELL
    if [[ $2 ]] ; then
        if (( $2 == 1 )) ; then
            echo $1
        else
            factorial $(( $1 * $2 )) $(( $2 - 1 ))
        fi
    else
        factorial $1 $(( $1 - 1 ))
    fi
}

factorial $1

关于bash - 递归调用函数时如何阻止bash创建子shell,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33568055/

相关文章:

linux - 几秒钟后终止作业并处理循环中的下一步

c - 使用堆栈的中缀到后缀的转换

linux - Bash if 语句 : Can I do an assignment and comparison?

java - 通过二分查找递归帮助(Java)

java - 索引越界异常但无法找出问题所在

linux - 从 VPS 备份所有网页文件

bash - 文件命令中的进程替换问题

linux - 在 bash 脚本中发出回显变量

javascript - 从 Node js 应用程序执行命令

java - 递归Java,检查节点之间的冲突