【发布时间】:2023-04-03 08:10:01
【问题描述】:
这是一个计算阶乘的简单 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
由于子外壳创建,存在其他不需要的方面。
#!/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!
【问题讨论】:
-
命令替换总是启动一个新的子shell;你无法改变它。
-
函数调用不创建子shell。手册说:“函数在当前 shell 的上下文中执行;没有创建新的进程来解释它们”。但是,您使用“$(...)”。
-
根据手册,确实如此。但是当我不小心尝试计算“阶乘 500”时,我也很惊讶,系统监视器显示了很长的子进程列表。
-
请注意,使用
$(…)需要子shell(但$((…))不需要)。
标签: bash shell recursion process