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

📄 complexfunct.html

📁 BASH Shell 编程 经典教程 《高级SHELL脚本编程》中文版
💻 HTML
📖 第 1 页 / 共 2 页
字号:
<!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="functions.html"><LINKREL="PREVIOUS"TITLE="函数"HREF="functions.html"><LINKREL="NEXT"TITLE="局部变量"HREF="localvar.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="functions.html"ACCESSKEY="P">前一页</A></TD><TDWIDTH="80%"ALIGN="center"VALIGN="bottom">23. 函数</TD><TDWIDTH="10%"ALIGN="right"VALIGN="bottom"><AHREF="localvar.html"ACCESSKEY="N">下一页</A></TD></TR></TABLE><HRALIGN="LEFT"WIDTH="100%"></DIV><DIVCLASS="SECT1"><H1CLASS="SECT1"><ANAME="COMPLEXFUNCT">23.1. 复杂函数和函数复杂性</A></H1><P>函数可以处理传递给它的参数, 			并且能返回它的<AHREF="exit-status.html#EXITSTATUSREF">退出状态码</A>给脚本, 以便后续处理. </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;function_name $arg1 $arg2</PRE></FONT></TD></TR></TABLE><P>函数以位置来引用传递过来的参数(就好像它们是<AHREF="internalvariables.html#POSPARAMREF">位置参数</A>), 	例如, <CODECLASS="VARNAME">$1</CODE>, <CODECLASS="VARNAME">$2</CODE>, 等等. </P><DIVCLASS="EXAMPLE"><HR><ANAME="EX60"></A><P><B>例子 23-2. 带参数的函数</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;# 函数和参数  3&nbsp;  4&nbsp;DEFAULT=default                             # 默认参数值.   5&nbsp;  6&nbsp;func2 () {  7&nbsp;   if [ -z "$1" ]                           # 第一个参数是否长度为零?   8&nbsp;   then  9&nbsp;     echo "-Parameter #1 is zero length.-"  # 或者没有参数被传递进来.  10&nbsp;   else 11&nbsp;     echo "-Param #1 is \"$1\".-" 12&nbsp;   fi 13&nbsp; 14&nbsp;   variable=${1-$DEFAULT}                   #  这里的参数替换 15&nbsp;   echo "variable = $variable"              #+ 表示什么?  16&nbsp;                                            #  --------------------------- 17&nbsp;                                            #  为了区分没有参数的情况,  18&nbsp;                                            #+ 和只有一个null参数的情况.  19&nbsp; 20&nbsp;   if [ "$2" ] 21&nbsp;   then 22&nbsp;     echo "-Parameter #2 is \"$2\".-" 23&nbsp;   fi 24&nbsp; 25&nbsp;   return 0 26&nbsp;} 27&nbsp; 28&nbsp;echo 29&nbsp;    30&nbsp;echo "Nothing passed."    31&nbsp;func2                          # 不带参数调用 32&nbsp;echo 33&nbsp; 34&nbsp; 35&nbsp;echo "Zero-length parameter passed." 36&nbsp;func2 ""                       # 使用0长度的参数进行调用 37&nbsp;echo 38&nbsp; 39&nbsp;echo "Null parameter passed." 40&nbsp;func2 "$uninitialized_param"   # 使用未初始化的参数进行调用 41&nbsp;echo 42&nbsp; 43&nbsp;echo "One parameter passed."    44&nbsp;func2 first           # 带一个参数调用 45&nbsp;echo 46&nbsp; 47&nbsp;echo "Two parameters passed."    48&nbsp;func2 first second    # 带两个参数调用 49&nbsp;echo 50&nbsp; 51&nbsp;echo "\"\" \"second\" passed." 52&nbsp;func2 "" second       # 带两个参数调用,  53&nbsp;echo                  # 第一个参数长度为0, 第二个参数是由ASCII码组成的字符串.  54&nbsp; 55&nbsp;exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="IMPORTANT"><P></P><TABLECLASS="IMPORTANT"WIDTH="100%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="./images/important.gif"HSPACE="5"ALT="Important"></TD><TDALIGN="LEFT"VALIGN="TOP"><P>也可以使用<AHREF="othertypesv.html#SHIFTREF">shift</A>命令来处理传递给函数的参数(请参考<AHREF="assortedtips.html#MULTIPLICATION">例子 33-15</A>). </P></TD></TR></TABLE></DIV><P>但是, 传给脚本的命令行参数怎么办? 		  在函数内部, 这些传给脚本的命令行参数也可见么? 		  好, 现在让我们弄清楚这个问题. </P><DIVCLASS="EXAMPLE"><HR><ANAME="FUNCCMDLINEARG"></A><P><B>例子 23-3. 函数与传递给脚本的命令行参数</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;# func-cmdlinearg.sh  3&nbsp;#  调用这个脚本, 并且带一个命令行参数.   4&nbsp;#+ 类似于 $0 arg1.  5&nbsp;  6&nbsp;  7&nbsp;func ()  8&nbsp;  9&nbsp;{ 10&nbsp;echo "$1" 11&nbsp;} 12&nbsp; 13&nbsp;echo "First call to function: no arg passed." 14&nbsp;echo "See if command-line arg is seen." 15&nbsp;func 16&nbsp;# 不行! 命令行参数不可见.  17&nbsp; 18&nbsp;echo "============================================================" 19&nbsp;echo 20&nbsp;echo "Second call to function: command-line arg passed explicitly." 21&nbsp;func $1 22&nbsp;# 现在可见了!  23&nbsp; 24&nbsp;exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><P>与别的编程语言相比, shell脚本一般只会传值给函数. 		  如果把变量名(事实上就是指针)作为参数传递给函数的话, 		  那将被解释为字面含义, 也就是被看作字符串. 	<EM>函数只会以字面含义来解释函数参数. </EM></P><P><AHREF="ivr.html#IVRREF">变量的间接引用</A>(请参考<AHREF="bashver2.html#EX78">例子 34-2</A>)提供了一种笨拙的机制, 来将变量指针传递给函数. 	    </P><DIVCLASS="EXAMPLE"><HR><ANAME="INDFUNC"></A><P><B>例子 23-4. 将一个间接引用传递给函数</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;# ind-func.sh: 将一个间接引用传递给函数.   3&nbsp;  4&nbsp;echo_var ()  5&nbsp;{  6&nbsp;echo "$1"  7&nbsp;}  8&nbsp;  9&nbsp;message=Hello 10&nbsp;Hello=Goodbye 11&nbsp; 12&nbsp;echo_var "$message"        # Hello 13&nbsp;# 现在,让我们传递一个间接引用给函数.  14&nbsp;echo_var "${!message}"     # Goodbye 15&nbsp; 16&nbsp;echo "-------------" 17&nbsp; 18&nbsp;# 如果我们改变"hello"变量的值会发生什么?  19&nbsp;Hello="Hello, again!" 20&nbsp;echo_var "$message"        # Hello 21&nbsp;echo_var "${!message}"     # Hello, again! 22&nbsp; 23&nbsp;exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><P>接下来的一个逻辑问题就是, 			将参数传递给函数<EM>之后</EM>, 			参数能否被解除引用. 	  </P><DIVCLASS="EXAMPLE"><HR><ANAME="DEREFERENCECL"></A><P><B>例子 23-5. 对一个传递给函数的参数进行解除引用的操作</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;# dereference.sh  3&nbsp;# 对一个传递给函数的参数进行解除引用的操作.   4&nbsp;# 此脚本由Bruce W. Clare所编写.   5&nbsp;  6&nbsp;dereference ()  7&nbsp;{  8&nbsp;     y=\$"$1"   # 变量名.   9&nbsp;     echo $y    # $Junk 10&nbsp; 11&nbsp;     x=`eval "expr \"$y\" "` 12&nbsp;     echo $1=$x 13&nbsp;     eval "$1=\"Some Different Text \""  # 赋新值.  14&nbsp;} 15&nbsp; 16&nbsp;Junk="Some Text" 17&nbsp;echo $Junk "before"    # Some Text before 18&nbsp; 19&nbsp;dereference Junk 20&nbsp;echo $Junk "after"     # Some Different Text after 21&nbsp; 22&nbsp;exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="EXAMPLE"><HR><ANAME="REFPARAMS"></A><P><B>例子 23-6. 再来一次, 对一个传递给函数的参数进行解除引用的操作</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;# ref-params.sh: 解除传递给函数的参数引用.  3&nbsp;#                (复杂的例子)  4&nbsp;  5&nbsp;ITERATIONS=3  # 取得输入的次数.   6&nbsp;icount=1  7&nbsp;  8&nbsp;my_read () {  9&nbsp;  #  用my_read varname这种形式来调用,  10&nbsp;  #+ 将之前用括号括起的值作为默认值输出,  11&nbsp;  #+ 然后要求输入一个新值.  12&nbsp; 13&nbsp;  local local_var 14&nbsp; 15&nbsp;  echo -n "Enter a value " 16&nbsp;  eval 'echo -n "[$'$1'] "'  #  之前的值.  17&nbsp;# eval echo -n "[\$$1] "     #  更容易理解,  18&nbsp;                             #+ 但会丢失用户在尾部输入的空格.  19&nbsp;  read local_var 20&nbsp;  [ -n "$local_var" ] &#38;&#38; eval $1=\$local_var 21&nbsp; 22&nbsp;  # "与列表": 如果"local_var"的测试结果为true, 则把变量"$1"的值赋给它.  23&nbsp;} 24&nbsp; 25&nbsp;echo 26&nbsp; 27&nbsp;while [ "$icount" -le "$ITERATIONS" ] 28&nbsp;do 29&nbsp;  my_read var 30&nbsp;  echo "Entry #$icount = $var" 31&nbsp;  let "icount += 1" 32&nbsp;  echo 33&nbsp;done   34&nbsp; 35&nbsp; 36&nbsp;# 感谢Stephane Chazelas提供这个例子.  37&nbsp; 38&nbsp;exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><P></P><DIVCLASS="VARIABLELIST"><P><B><ANAME="EXITRETURN1"></A>退出与返回</B></P><DL><DT><BCLASS="COMMAND">退出状态码</B></DT><DD><P>函数返回一个值, 被称为<ICLASS="FIRSTTERM">退出状态码</I>. 			  退出状态码可以由<BCLASS="COMMAND">return</B>命令明确指定, 	      也可以由函数中最后一条命令的退出状态码来指定(如果成功则返回<SPANCLASS="RETURNVALUE">0</SPAN>, 		  否则返回非0值). 		  可以在脚本中使用<AHREF="internalvariables.html#XSTATVARREF">$?</A>来引用<AHREF="exit-status.html#EXITSTATUSREF">退出状态码</A>. 		  因为有了这种机制, 		  所以脚本函数也可以象C函数一样有<SPANCLASS="QUOTE">"返回值"</SPAN>. </P></DD><DT><BCLASS="COMMAND">return</B></DT><DD><P><ANAME="RETURNREF"></A></P><P>终止一个函数. <BCLASS="COMMAND">return</B>命令			<ANAME="AEN14444"HREF="#FTN.AEN14444"><SPANCLASS="footnote">[1]</SPAN></A>	      可选的允许带一个<EM>整型</EM>参数, 		  这个整数将作为函数的<SPANCLASS="QUOTE">"退出状态码"</SPAN>返回给调用这个函数的脚本, 		  并且这个整数也被赋值给变量<AHREF="internalvariables.html#XSTATVARREF">$?</A>. </P><DIVCLASS="EXAMPLE"><HR><ANAME="MAX"></A><P><B>例子 23-7. 取两个数中的最大值</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;# max.sh: 取两个整数中的最大值.   3&nbsp;  4&nbsp;E_PARAM_ERR=-198    # 如果传给函数的参数少于2个时, 就返回这个值.   5&nbsp;EQUAL=-199          # 如果两个整数相等时, 返回这个值.   6&nbsp;#  任意超出范围的  7&nbsp;#+ 参数值都可能传递到函数中.   8&nbsp;  9&nbsp;max2 ()             # 返回两个整数中的最大值.  10&nbsp;{                   # 注意: 参与比较的数必须小于257.  11&nbsp;if [ -z "$2" ] 12&nbsp;then 13&nbsp;  return $E_PARAM_ERR 14&nbsp;fi 15&nbsp; 16&nbsp;if [ "$1" -eq "$2" ] 17&nbsp;then 18&nbsp;  return $EQUAL 19&nbsp;else 20&nbsp;  if [ "$1" -gt "$2" ] 21&nbsp;  then 22&nbsp;    return $1 23&nbsp;  else 24&nbsp;    return $2 25&nbsp;  fi 26&nbsp;fi 27&nbsp;} 28&nbsp; 29&nbsp;max2 33 34 30&nbsp;return_val=$? 31&nbsp; 32&nbsp;if [ "$return_val" -eq $E_PARAM_ERR ] 33&nbsp;then 34&nbsp;  echo "Need to pass two parameters to the function." 35&nbsp;elif [ "$return_val" -eq $EQUAL ] 36&nbsp;  then 37&nbsp;    echo "The two numbers are equal." 38&nbsp;else 39&nbsp;    echo "The larger of the two numbers is $return_val." 40&nbsp;fi   41&nbsp; 42&nbsp;   43&nbsp;exit 0 44&nbsp; 45&nbsp;#  练习(简单): 46&nbsp;#  ----------- 47&nbsp;#  把这个脚本转化为交互式脚本,  48&nbsp;#+ 也就是, 修改这个脚本, 让其要求调用者输入2个数. </PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="TIP"><P></P><TABLECLASS="TIP"WIDTH="90%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="./images/tip.gif"HSPACE="5"ALT="Tip"></TD><TDALIGN="LEFT"VALIGN="TOP"><P>为了让函数可以返回字符串或是数组, 				可以使用一个在函数外可见的专用全局变量. 	        <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;count_lines_in_etc_passwd()  2&nbsp;{  3&nbsp;  [[ -r /etc/passwd ]] &#38;&#38; REPLY=$(echo $(wc -l &#60; /etc/passwd))  4&nbsp;  #  如果/etc/passwd是可读的, 那么就把REPLY设置为文件的行数.   5&nbsp;  #  这样就可以同时返回参数值与状态信息.   6&nbsp;  #  'echo'看上去没什么用, 可是 . . .  7&nbsp;  #+ 它的作用是删除输出中的多余空白字符.   8&nbsp;}  9&nbsp; 10&nbsp;if count_lines_in_etc_passwd 11&nbsp;then 12&nbsp;  echo "There are $REPLY lines in /etc/passwd." 13&nbsp;else 14&nbsp;  echo "Cannot count lines in /etc/passwd." 15&nbsp;fi   16&nbsp; 17&nbsp;# 感谢, S.C.</PRE></FONT></TD></TR></TABLE>	    </P></TD></TR></TABLE></DIV><DIV

⌨️ 快捷键说明

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