📄 recursionsct.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><HTML><HEAD><TITLE>递归</TITLE><METANAME="GENERATOR"CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINKREL="HOME"TITLE="高级Bash脚本编程指南"HREF="index.html"><LINKREL="UP"TITLE="杂项"HREF="miscellany.html"><LINKREL="PREVIOUS"TITLE="测试和比较: 一种可选的方法"HREF="testsandcomparisons.html"><LINKREL="NEXT"TITLE="将脚本彩色化"HREF="colorizing.html"></HEAD><BODYCLASS="SECT1"BGCOLOR="#FFFFFF"TEXT="#000000"LINK="#0000FF"VLINK="#840084"ALINK="#0000FF"><DIVCLASS="NAVHEADER"><TABLESUMMARY="Header navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><THCOLSPAN="3"ALIGN="center">高级Bash脚本编程指南: 一本深入学习shell脚本艺术的书籍</TH></TR><TR><TDWIDTH="10%"ALIGN="left"VALIGN="bottom"><AHREF="testsandcomparisons.html"ACCESSKEY="P">前一页</A></TD><TDWIDTH="80%"ALIGN="center"VALIGN="bottom">33. 杂项</TD><TDWIDTH="10%"ALIGN="right"VALIGN="bottom"><AHREF="colorizing.html"ACCESSKEY="N">下一页</A></TD></TR></TABLE><HRALIGN="LEFT"WIDTH="100%"></DIV><DIVCLASS="SECT1"><H1CLASS="SECT1"><ANAME="RECURSIONSCT">33.4. 递归</A></H1><P>脚本是否可以<AHREF="localvar.html#RECURSIONREF">递归</A>调用自身? 当然可以. </P><DIVCLASS="EXAMPLE"><HR><ANAME="RECURSE"></A><P><B>例子 33-8. 递归调用自身的(没用的)脚本</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 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 # 每个子脚本都做同样的事情, until 19 #+ 直到产生的变量$i等于$MAXVAL为止. 20 21 # 如果使用"while"循环来代替"if/then"测试结构的话, 会产生问题. 22 # 解释一下为什么. 23 24 exit 0 25 26 # 注意: 27 # ----- 28 # 脚本想要正常的工作, 就必须具备可执行权限. 29 # 即使使用"sh"命令来调用它, 但是没有设置正确的权限一样会导致问题. 30 # 解释一下原因. </PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="EXAMPLE"><HR><ANAME="PBOOK"></A><P><B>例子 33-9. 递归调用自身的(有用的)脚本</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # pb.sh: 电话本 3 4 # 由Rick Boivie编写, 已经得到作者授权, 可以在本书中使用. 5 # 本书作者做了一些修改. 6 7 MINARGS=1 # 脚本至少需要一个参数. 8 DATAFILE=./phonebook 9 # 当前目录下, 10 #+ 必须有一个名字为"phonebook"的数据文件. 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 # 因此, 在这句之后, 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 #+ 那这个脚本就*只*会打印包含所有参数的行. </PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="EXAMPLE"><HR><ANAME="USRMNT"></A><P><B>例子 33-10. 另一个递归调用自身的(有用的)脚本</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # usrmnt.sh, 由Anthony Richardson编写, 3 # 经过作者授权, 可以在本书中使用. 4 5 # 用法: usrmnt.sh 6 # 描述: 挂载设备, 调用这个脚本的用户必须属于 7 # /etc/sudoers文件中的MNTUSERS组. 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) 我还发现, 通过使用组, 47 # 我能够更容易的完成这个任务. 48 49 # 3) 这个方法可以将root访问mount命令的权利, 50 # 赋予任何具有合适权限的用户, 51 # 所以一定要小心那些被你赋予访问权限的用户. 52 # 你可以开发出类似于mntfloppy, mntcdrom, 53 # 和mntsamba脚本, 将访问类型分类, 54 # 然后你就可以使用上面所讲的这种技术, 55 # 获得对mount命令更好的控制. </PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="CAUTION"><P></P><TABLECLASS="CAUTION"WIDTH="100%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="./images/caution.gif"HSPACE="5"ALT="Caution"></TD><TDALIGN="LEFT"VALIGN="TOP"><P>过多层次的递归会耗尽脚本的栈空间, 引起段错误. </P></TD></TR></TABLE></DIV></DIV><DIVCLASS="NAVFOOTER"><HRALIGN="LEFT"WIDTH="100%"><TABLESUMMARY="Footer navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><AHREF="testsandcomparisons.html"ACCESSKEY="P">前一页</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="index.html"ACCESSKEY="H">首页</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><AHREF="colorizing.html"ACCESSKEY="N">下一页</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">测试和比较: 一种可选的方法</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="miscellany.html"ACCESSKEY="U">上一级</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">将脚本<SPANCLASS="QUOTE">"彩色化"</SPAN></TD></TR></TABLE></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -