⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 complexfunct.html

📁 BASH Shell 编程 经典教程 《高级SHELL脚本编程》中文版
💻 HTML
📖 第 1 页 / 共 2 页
字号:
CLASS="EXAMPLE"><HR><ANAME="EX61"></A><P><B>例子 23-8. 将阿拉伯数字转化为罗马数字</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;  3&nbsp;# 将阿拉伯数字转化为罗马数字  4&nbsp;# 范围: 0 - 200  5&nbsp;# 比较粗糙, 但可以正常工作.   6&nbsp;  7&nbsp;# 扩展范围, 并且完善这个脚本, 作为练习.   8&nbsp;  9&nbsp;# 用法: roman number-to-convert 10&nbsp; 11&nbsp;LIMIT=200 12&nbsp;E_ARG_ERR=65 13&nbsp;E_OUT_OF_RANGE=66 14&nbsp; 15&nbsp;if [ -z "$1" ] 16&nbsp;then 17&nbsp;  echo "Usage: `basename $0` number-to-convert" 18&nbsp;  exit $E_ARG_ERR 19&nbsp;fi   20&nbsp; 21&nbsp;num=$1 22&nbsp;if [ "$num" -gt $LIMIT ] 23&nbsp;then 24&nbsp;  echo "Out of range!" 25&nbsp;  exit $E_OUT_OF_RANGE 26&nbsp;fi   27&nbsp; 28&nbsp;to_roman ()   # 在第一次调用函数前必须先定义它.  29&nbsp;{ 30&nbsp;number=$1 31&nbsp;factor=$2 32&nbsp;rchar=$3 33&nbsp;let "remainder = number - factor" 34&nbsp;while [ "$remainder" -ge 0 ] 35&nbsp;do 36&nbsp;  echo -n $rchar 37&nbsp;  let "number -= factor" 38&nbsp;  let "remainder = number - factor" 39&nbsp;done   40&nbsp; 41&nbsp;return $number 42&nbsp;       # 练习: 43&nbsp;       # ----- 44&nbsp;       # 解释这个函数是如何工作的.  45&nbsp;       # 提示: 依靠不断的除, 来分割数字.  46&nbsp;} 47&nbsp;    48&nbsp; 49&nbsp;to_roman $num 100 C 50&nbsp;num=$? 51&nbsp;to_roman $num 90 LXXXX 52&nbsp;num=$? 53&nbsp;to_roman $num 50 L 54&nbsp;num=$? 55&nbsp;to_roman $num 40 XL 56&nbsp;num=$? 57&nbsp;to_roman $num 10 X 58&nbsp;num=$? 59&nbsp;to_roman $num 9 IX 60&nbsp;num=$? 61&nbsp;to_roman $num 5 V 62&nbsp;num=$? 63&nbsp;to_roman $num 4 IV 64&nbsp;num=$? 65&nbsp;to_roman $num 1 I 66&nbsp; 67&nbsp;echo 68&nbsp; 69&nbsp;exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><P>也请参考<AHREF="testbranch.html#ISALPHA">例子 10-28</A>. </P><DIVCLASS="IMPORTANT"><P></P><TABLECLASS="IMPORTANT"WIDTH="90%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="./images/important.gif"HSPACE="5"ALT="Important"></TD><TDALIGN="LEFT"VALIGN="TOP"><P>函数所能返回最大的正整数是255. 			<BCLASS="COMMAND">return</B>命令与<AHREF="exit-status.html#EXITSTATUSREF">退出状态码</A>的概念被紧密联系在一起, 并且退出状态码的值受此限制. 	      幸运的是, 如果想让函数返回大整数的话, 有好多种不同的<AHREF="assortedtips.html#RVT">工作区</A>能够应付这个情况. 	      </P><DIVCLASS="EXAMPLE"><HR><ANAME="RETURNTEST"></A><P><B>例子 23-9. 测试函数最大的返回值</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;# return-test.sh  3&nbsp;  4&nbsp;# 函数所能返回的最大正整数为255.   5&nbsp;  6&nbsp;return_test ()         # 传给函数什么值, 就返回什么值.   7&nbsp;{  8&nbsp;  return $1  9&nbsp;} 10&nbsp; 11&nbsp;return_test 27         # o.k. 12&nbsp;echo $?                # 返回27. 13&nbsp;   14&nbsp;return_test 255        # 依然是o.k. 15&nbsp;echo $?                # 返回255. 16&nbsp; 17&nbsp;return_test 257        # 错误! 18&nbsp;echo $?                # 返回1 (对应各种错误的返回码).  19&nbsp; 20&nbsp;# ====================================================== 21&nbsp;return_test -151896    # 能返回一个大负数么?  22&nbsp;echo $?                # 能否返回-151896? 23&nbsp;                       # 显然不行! 只返回了168. 24&nbsp;#  Bash 2.05b以前的版本 25&nbsp;#+ 允许返回大负数.  26&nbsp;#  Bash的新版本(2.05b之后)修正了这个漏洞.  27&nbsp;#  这可能会影响以前所编写的脚本.  28&nbsp;#  一定要小心!  29&nbsp;# ====================================================== 30&nbsp; 31&nbsp;exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><P>如果你想获得大整数<SPANCLASS="QUOTE">"返回值"</SPAN>的话, 			其实最简单的办法就是将<SPANCLASS="QUOTE">"要返回的值"</SPAN>保存到一个全局变量中.	        <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;Return_Val=   # 用于保存函数特大返回值的全局变量.   2&nbsp;  3&nbsp;alt_return_test ()  4&nbsp;{  5&nbsp;  fvar=$1  6&nbsp;  Return_Val=$fvar  7&nbsp;  return   # 返回0 (成功).   8&nbsp;}  9&nbsp; 10&nbsp;alt_return_test 1 11&nbsp;echo $?                              # 0 12&nbsp;echo "return value = $Return_Val"    # 1 13&nbsp; 14&nbsp;alt_return_test 256 15&nbsp;echo "return value = $Return_Val"    # 256 16&nbsp; 17&nbsp;alt_return_test 257 18&nbsp;echo "return value = $Return_Val"    # 257 19&nbsp; 20&nbsp;alt_return_test 25701 21&nbsp;echo "return value = $Return_Val"    #25701</PRE></FONT></TD></TR></TABLE>            </P><P>一种更优雅的做法是在函数中使用<BCLASS="COMMAND">echo</B>命令将<SPANCLASS="QUOTE">"返回值输出到<TTCLASS="FILENAME">stdout</TT>"</SPAN>, 			然后使用<AHREF="commandsub.html#COMMANDSUBREF">命令替换</A>来捕捉此值. 			请参考<AHREF="assortedtips.html">Section 33.7</A>中<AHREF="assortedtips.html#RVT">关于这种用法的讨论</A>. </P><DIVCLASS="EXAMPLE"><HR><ANAME="MAX2"></A><P><B>例子 23-10. 比较两个大整数</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;# max2.sh: 取两个大整数中的最大值.   3&nbsp;  4&nbsp;#  这是前一个例子"max.sh"的修改版,   5&nbsp;#+ 这个版本可以比较两个大整数.   6&nbsp;  7&nbsp;EQUAL=0             # 如果两个值相等, 那就返回这个值.   8&nbsp;E_PARAM_ERR=-99999  # 没有足够多的参数传递给函数.   9&nbsp;#           ^^^^^^    任意超出范围的参数都可以传递进来.  10&nbsp; 11&nbsp;max2 ()             # "返回"两个整数中最大的那个.  12&nbsp;{ 13&nbsp;if [ -z "$2" ] 14&nbsp;then 15&nbsp;  echo $E_PARAM_ERR 16&nbsp;  return 17&nbsp;fi 18&nbsp; 19&nbsp;if [ "$1" -eq "$2" ] 20&nbsp;then 21&nbsp;  echo $EQUAL 22&nbsp;  return 23&nbsp;else 24&nbsp;  if [ "$1" -gt "$2" ] 25&nbsp;  then 26&nbsp;    retval=$1 27&nbsp;  else 28&nbsp;    retval=$2 29&nbsp;  fi 30&nbsp;fi 31&nbsp; 32&nbsp;echo $retval        # 输出(到stdout), 而没有用返回值.  33&nbsp;                    # 为什么?  34&nbsp;} 35&nbsp; 36&nbsp; 37&nbsp;return_val=$(max2 33001 33997) 38&nbsp;#            ^^^^             函数名 39&nbsp;#                 ^^^^^ ^^^^^ 传递进来的参数 40&nbsp;#  这其实是命令替换的一种形式:  41&nbsp;#+ 可以把函数看作为一个命令,  42&nbsp;#+ 然后把函数的stdout赋值给变量"return_val."  43&nbsp; 44&nbsp; 45&nbsp;# ========================= OUTPUT ======================== 46&nbsp;if [ "$return_val" -eq "$E_PARAM_ERR" ] 47&nbsp;  then 48&nbsp;  echo "Error in parameters passed to comparison function!" 49&nbsp;elif [ "$return_val" -eq "$EQUAL" ] 50&nbsp;  then 51&nbsp;    echo "The two numbers are equal." 52&nbsp;else 53&nbsp;    echo "The larger of the two numbers is $return_val." 54&nbsp;fi 55&nbsp;# ========================================================= 56&nbsp;   57&nbsp;exit 0 58&nbsp; 59&nbsp;#  练习: 60&nbsp;#  ----- 61&nbsp;#  1) 找到一种更优雅的方法,  62&nbsp;#+    来测试传递给函数的参数.  63&nbsp;#  2) 简化"输出"段的if/then结构.  64&nbsp;#  3) 重写这个脚本, 使其能够从命令行参数中获得输入. </PRE></FONT></TD></TR></TABLE><HR></DIV><P>这是另一个能够捕捉函数<SPANCLASS="QUOTE">"返回值"</SPAN>的例子. 			要想搞明白这个例子, 需要一些<AHREF="awk.html#AWKREF">awk</A>的知识. 	    <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;month_length ()  # 把月份作为参数.   2&nbsp;{                # 返回该月包含的天数.   3&nbsp;monthD="31 28 31 30 31 30 31 31 30 31 30 31"  # 作为局部变量声明?   4&nbsp;echo "$monthD" | awk '{ print $'"${1}"' }'    # 小技巧.   5&nbsp;#                             ^^^^^^^^^  6&nbsp;# 传递给函数的参数($1 -- 月份号), 然后传给awk.   7&nbsp;# Awk把参数解释为"print $1 . . . print $12"(这依赖于月份号)  8&nbsp;# 这是一个模版, 用于将参数传递给内嵌awk的脚本:   9&nbsp;#                                 $'"${script_parameter}"' 10&nbsp; 11&nbsp;#  需要做一些错误检查, 来保证月份号正确, 在范围(1-12)之间,  12&nbsp;#+ 别忘了检查闰年的二月.  13&nbsp;} 14&nbsp; 15&nbsp;# ---------------------------------------------- 16&nbsp;# 用例: 17&nbsp;month=4        # 以四月为例.  18&nbsp;days_in=$(month_length $month) 19&nbsp;echo $days_in  # 30 20&nbsp;# ----------------------------------------------</PRE></FONT></TD></TR></TABLE></P><P>也请参考<AHREF="contributed-scripts.html#DAYSBETWEEN">例子 A-7</A>. </P><P><KBDCLASS="USERINPUT">练习:</KBD> 使用目前我们已经学到的知识, 	      来扩展之前的例子<AHREF="complexfunct.html#EX61">将阿拉伯数字转化为罗马数字</A>, 		 让它能够接受任意大的输入. </P></TD></TR></TABLE></DIV></DD></DL></DIV><P></P><DIVCLASS="VARIABLELIST"><P><B><ANAME="REDSTDINFUNC1"></A>重定向</B></P><DL><DT><TTCLASS="REPLACEABLE"><I>重定向函数的stdin</I></TT></DT><DD><P>函数本质上其实就是一个<AHREF="special-chars.html#CODEBLOCKREF">代码块</A>, 			这就意味着它的<TTCLASS="FILENAME">stdin</TT>可以被重定向(比如<AHREF="special-chars.html#EX8">例子 3-1</A>). </P><DIVCLASS="EXAMPLE"><HR><ANAME="REALNAME"></A><P><B>例子 23-11. 从username中取得用户的真名</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;# realname.sh  3&nbsp;#  4&nbsp;# 依靠username, 从/etc/passwd中获得"真名".   5&nbsp;  6&nbsp;  7&nbsp;ARGCOUNT=1       # 需要一个参数.   8&nbsp;E_WRONGARGS=65  9&nbsp; 10&nbsp;file=/etc/passwd 11&nbsp;pattern=$1 12&nbsp; 13&nbsp;if [ $# -ne "$ARGCOUNT" ] 14&nbsp;then 15&nbsp;  echo "Usage: `basename $0` USERNAME" 16&nbsp;  exit $E_WRONGARGS 17&nbsp;fi   18&nbsp; 19&nbsp;file_excerpt ()  # 按照要求的模式来扫描文件, 然后打印文件相关的部分.  20&nbsp;{ 21&nbsp;while read line  # "while"并不一定非得有"[ condition ]"不可.  22&nbsp;do 23&nbsp;  echo "$line" | grep $1 | awk -F":" '{ print $5 }'  # awk用":"作为界定符.  24&nbsp;done 25&nbsp;} &#60;$file  # 重定向到函数的stdin.  26&nbsp; 27&nbsp;file_excerpt $pattern 28&nbsp; 29&nbsp;# 是的, 整个脚本其实可以被缩减为 30&nbsp;#       grep PATTERN /etc/passwd | awk -F":" '{ print $5 }' 31&nbsp;# 或 32&nbsp;#       awk -F: '/PATTERN/ {print $5}' 33&nbsp;# 或 34&nbsp;#       awk -F: '($1 == "username") { print $5 }' # 从username中获得真名.  35&nbsp;# 但是, 这些起不到示例的作用.  36&nbsp; 37&nbsp;exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><P>还有一个办法, 或许能够更好的理解重定向函数的<TTCLASS="FILENAME">stdin</TT>. 			它在函数内添加了一对大括号, 			并且将重定向<TTCLASS="FILENAME">stdin</TT>的行为放在这对添加的大括号上. 	       <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;# 用下面的方法来代替它:  2&nbsp;Function ()  3&nbsp;{  4&nbsp; ...  5&nbsp; } &#60; file  6&nbsp;  7&nbsp;# 试试这个:   8&nbsp;Function ()  9&nbsp;{ 10&nbsp;  { 11&nbsp;    ... 12&nbsp;   } &#60; file 13&nbsp;} 14&nbsp; 15&nbsp;# 同样的, 16&nbsp; 17&nbsp;Function ()  # 没问题. 18&nbsp;{ 19&nbsp;  { 20&nbsp;   echo $* 21&nbsp;  } | tr a b 22&nbsp;} 23&nbsp; 24&nbsp;Function ()  # 不行.  25&nbsp;{ 26&nbsp;  echo $* 27&nbsp;} | tr a b   # 这儿的内嵌代码块是被强制的.  28&nbsp; 29&nbsp; 30&nbsp;# 感谢, S.C.</PRE></FONT></TD></TR></TABLE>           </P></DD></DL></DIV></DIV><H3CLASS="FOOTNOTES">注意事项</H3><TABLEBORDER="0"CLASS="FOOTNOTES"WIDTH="100%"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="5%"><ANAME="FTN.AEN14444"HREF="complexfunct.html#AEN14444"><SPANCLASS="footnote">[1]</SPAN></A></TD><TDALIGN="LEFT"VALIGN="TOP"WIDTH="95%"><P><BCLASS="COMMAND">return</B>命令是Bash<AHREF="internal.html#BUILTINREF">内建命令builtin</A>. 			</P></TD></TR></TABLE><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="functions.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="localvar.html"ACCESSKEY="N">下一页</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">函数</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="functions.html"ACCESSKEY="U">上一级</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">局部变量</TD></TR></TABLE></DIV></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -