当前位置: 首页 > 文档资料 > Shell 中文文档 >

33.4. 递归

优质
小牛编辑
138浏览
2023-12-01

脚本是否能 递归地调用自己本身? 当然可以.

例子 33-8. 递归调用自己本身的(无用)脚本

   1 #!/bin/bash
   2 # recurse.sh
   3
   4 #  脚本能否递归地调用自己?
   5 #  是的, 但这有什么实际的用处吗?
   6 #  (看下面的.)
   7
   8 RANGE=10
   9 MAXVAL=9
  10
  11 i=$RANDOM
  12 let "i %= $RANGE"  # 产生一个从 0 到 $RANGE - 1 之间的随机数.
  13
  14 if [ "$i" -lt "$MAXVAL" ]
  15 then
  16   echo "i = $i"
  17   ./$0             #  脚本递归地调用再生成一个和自己一样的实例.
  18 fi                 #  每个子脚本做的事都一样,
  19                    #+ 直到产生的变量 $i 和变量 $MAXVAL 相等.
  20
  21 #  用"while"循环代替"if/then"测试会引起错误.
  22 #  解释为什么会这样.
  23
  24 exit 0
  25
  26 # 注:
  27 # ----
  28 # 脚本要正确地工作必须有执行权限.
  29 # 这是指用"sh"命令来调用这个脚本而没有设置正确权限导致的问题.
  30 # 请解释原因.

例子 33-9. 递归调用自己本身的(有用)脚本

   1 #!/bin/bash
   2 # pb.sh: 电话本(phone book)
   3
   4 # 由Rick Boivie编写,已得到使用许可.
   5 # 由ABS文档作者修改.
   6
   7 MINARGS=1     #  脚本需要至少一个参数.
   8 DATAFILE=./phonebook
   9               #  在当前目录下名为"phonebook"的数据文件必须存在
  10               #
  11 PROGNAME=$0
  12 E_NOARGS=70   #  没有参数的错误值.
  13
  14 if [ $# -lt $MINARGS ]; then
  15       echo "Usage: "$PROGNAME" data"
  16       exit $E_NOARGS
  17 fi
  18
  19
  20 if [ $# -eq $MINARGS ]; then
  21       grep $1 "$DATAFILE"
  22       #  如果$DATAFILE文件不存在,'grep' 会打印一个错误信息.
  23 else
  24       ( shift; "$PROGNAME" $* ) | grep $1
  25       # 脚本递归调用本身.
  26 fi
  27
  28 exit 0        #  脚本在这儿退出.
  29               #  因此Therefore, 从这行开始可以写没有#开头的的注释行
  30 	      #
  31
  32 # ------------------------------------------------------------------------
  33 "phonebook"文件的例子:
  34
  35 John Doe        1555 Main St., Baltimore, MD 21228          (410) 222-3333
  36 Mary Moe        9899 Jones Blvd., Warren, NH 03787          (603) 898-3232
  37 Richard Roe     856 E. 7th St., New York, NY 10009          (212) 333-4567
  38 Sam Roe         956 E. 8th St., New York, NY 10009          (212) 444-5678
  39 Zoe Zenobia     4481 N. Baker St., San Francisco, SF 94338  (415) 501-1631
  40 # ------------------------------------------------------------------------
  41
  42 $bash pb.sh Roe
  43 Richard Roe     856 E. 7th St., New York, NY 10009          (212) 333-4567
  44 Sam Roe         956 E. 8th St., New York, NY 10009          (212) 444-5678
  45
  46 $bash pb.sh Roe Sam
  47 Sam Roe         956 E. 8th St., New York, NY 10009          (212) 444-5678
  48
  49 #  当超过一个参数传给这个脚本时,
  50 #+ 它只打印包含所有参数的行.

例子 33-10. 另一个递归调用自己本身的(有用)脚本

   1 #!/bin/bash
   2 # usrmnt.sh, 由Anthony Richardson编写
   3 # 得到允许在此使用.
   4
   5 # usage:       usrmnt.sh
   6 # 描述: 挂载设备, 调用者必须列在/etc/sudoers文件的MNTUSERS组里
   7 #
   8
   9 # ----------------------------------------------------------
  10 #  这是一个用户挂载设备的脚本,它用sudo来调用自己.
  11 #  只有拥有合适权限的用户才能用
  12
  13 #   usermount /dev/fd0 /mnt/floppy
  14
  15 # 来代替
  16
  17 #   sudo usermount /dev/fd0 /mnt/floppy
  18
  19 #  我使用相同的技术来处理我所有的sudo脚本,
  20 #+ 因为我觉得它很方便.
  21 # ----------------------------------------------------------
  22
  23 #  如果 SUDO_COMMAND 变量没有设置,我们不能通过sudo来运行脚本本身.
  24 #+ 传递用户的真实ID和组ID . . .
  25
  26 if [ -z "$SUDO_COMMAND" ]
  27 then
  28    mntusr=$(id -u) grpusr=$(id -g) sudo $0 $*
  29    exit 0
  30 fi
  31
  32 # 如果我们以sudo来调用运行,就会运行这儿.
  33 /bin/mount $* -o uid=$mntusr,gid=$grpusr
  34
  35 exit 0
  36
  37 # 附注 (由脚本作者加注):
  38 # -------------------------------------------------
  39
  40 # 1) Linux允许在/etc/fstab文件中使用"users"选项
  41 #    以使任何用户能挂载可移动的介质.
  42 #    但是, 在一个服务器上,
  43 #    我只想有限的几个用户可以存取可移动介质.
  44 #    我发现使用sudo可以有更多的控制.
  45
  46 # 2) 我也发现sudo能通过组更方便地达成目的.
  47 #
  48
  49 # 3) 这个方法使给予任何想给合适权限的人使用mount命令
  50 #    所以要小心使用.
  51 #    你也可以开发类似的脚本mntfloppy, mntcdrom,和 mntsamba来使mount命令得到更好的控制
  52 #
  53 #
  54 # 

 

过多层次的递归调用会耗尽脚本的堆栈空间,会引起段错误.

最后更新:

类似资料

  • 我对函数式编程很陌生,尤其是下面使用的Scheme。我正在尝试使以下函数是递归的,尾递归的。基本上,该函数的作用是对两个字符串的对齐方式进行评分。当给定两个字符串作为输入时,它会比较每个“列”字符,并根据在称为 scorer 的函数中实现的评分方案(由下面的代码中的函数调用)来累积该对齐的分数。 我有一个想法,用一个帮助函数来累积分数,但我不太确定如何去做,因此我该如何让下面的函数尾递归呢?

  • 5.2. 递归 函数可以是递归的,这意味着函数可以直接或间接的调用自身。对许多问题而言,递归是一种强有力的技术,例如处理递归的数据结构。在4.4节,我们通过遍历二叉树来实现简单的插入排序,在本章节,我们再次使用它来处理HTML文件。 下文的示例代码使用了非标准包 golang.org/x/net/html ,解析HTML。golang.org/x/... 目录下存储了一些由Go团队设计、维护,对网

  • 递归允许函数调用自身。 固定的代码步骤一次又一次地执行新值。 我们还必须设置标准来决定递归调用何时结束。 在下面的例子中,我们看到了二进制搜索的递归方法。 我们采用排序列表并将其索引范围作为递归函数的输入。 使用递归进行二进制搜索 我们使用python实现二进制搜索算法,如下所示。 我们使用一个有序的项目列表,并设计一个递归函数,以带有开始和结束索引作为输入的列表。 然后二进制搜索函数调用自己直到

  • 递归过程就是自称过程。 有两种递归:直接和间接。 在直接递归中,过程调用自身并在间接递归中,第一个过程调用第二个过程,该过程又调用第一个过程。 可以在许多数学算法中观察到递归。 例如,考虑计算数字的阶乘的情况。 一个数的因子由等式给出 - Fact (n) = n * fact (n-1) for n > 0 例如:5的阶乘是1 x 2 x 3 x 4 x 5 = 5 x阶乘4,这可以是显示递归

  • 我们在前面的主题中看到了recur语句,而'for'循环有点像循环, recur是Clojure中的一个真正的循环。 如果你有编程背景,你可能听说过尾递归,这是函数式语言的一个主要特性。 这种复现特殊形式是实现尾递归的形式。 正如单词“tail recursion”所示,必须在尾部位置调用recur。 换句话说,复发必须是最后评估的东西。 最简单的recur语句示例在'for'循环中使用。 在以下

  • 递归是以自相似的方式重复项目的过程。 在编程语言中,如果程序允许您在同一函数内调用函数,则称其为函数的递归调用。 void recursion() { recursion(); /* function calls itself */ } int main() { recursion(); } C编程语言支持递归,即调用自身的函数。 但是在使用递归时,程序员需要小心地从函数中定义退出条

开发工具

我的快递