loops1.html

来自「BASH Shell 编程 经典教程 《高级SHELL脚本编程》中文版」· HTML 代码 · 共 1,622 行 · 第 1/2 页

HTML
1,622
字号
></TD></TR></TABLE><HR></DIV><P><ICLASS="FIRSTTERM">for循环</I>的输出也可以通过管道传递到一个或多个命令中. </P><DIVCLASS="EXAMPLE"><HR><ANAME="SYMLINKS"></A><P><B>例子 10-10. 列出目录中所有的<AHREF="basic.html#SYMLINKREF">符号链接</A></B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;# symlinks.sh: 列出目录中所有的符号链接文件.  3&nbsp;  4&nbsp;  5&nbsp;directory=${1-`pwd`}  6&nbsp;#  如果没有其他特殊的指定,  7&nbsp;#+ 默认为当前工作目录.  8&nbsp;#  下边的代码块, 和上边这句等价.  9&nbsp;# ---------------------------------------------------------- 10&nbsp;# ARGS=1                 # 需要一个命令行参数. 11&nbsp;# 12&nbsp;# if [ $# -ne "$ARGS" ]  # 如果不是单个参数的话... 13&nbsp;# then 14&nbsp;#   directory=`pwd`      # 当前工作目录 15&nbsp;# else 16&nbsp;#   directory=$1 17&nbsp;# fi 18&nbsp;# ---------------------------------------------------------- 19&nbsp; 20&nbsp;echo "symbolic links in directory \"$directory\"" 21&nbsp; 22&nbsp;for file in "$( find $directory -type l )"   # -type l = 符号链接 23&nbsp;do 24&nbsp;  echo "$file" 25&nbsp;done | sort                                  # 否则的话, 列出的文件都是未经排序的. 26&nbsp;#  严格意义上说, 这里并不一定非要一个循环不可. 27&nbsp;#+ 因为"find"命令的输出将被扩展成一个单词.  28&nbsp;#  然而, 这种方式很容易理解也很容易说明. 29&nbsp; 30&nbsp;#  就像Dominik 'Aeneas' Schnitzer所指出的, 31&nbsp;#+ 如果没将$( find $directory -type l )用""引用起来的话, 32&nbsp;#+ 那么将会把一个带有空白部分的文件名拆分成以空白分隔的两部分(文件名允许有空白). 33&nbsp;#  即使这里只会取出每个参数的第一个域. 34&nbsp; 35&nbsp;exit 0 36&nbsp; 37&nbsp; 38&nbsp;# Jean Helou建议采用下边的方法:  39&nbsp; 40&nbsp;echo "symbolic links in directory \"$directory\"" 41&nbsp;# 当前IFS的备份. 要小心使用这个值. 42&nbsp;OLDIFS=$IFS 43&nbsp;IFS=: 44&nbsp; 45&nbsp;for file in $(find $directory -type l -printf "%p$IFS") 46&nbsp;do     #                              ^^^^^^^^^^^^^^^^ 47&nbsp;       echo "$file" 48&nbsp;       done|sort</PRE></FONT></TD></TR></TABLE><HR></DIV><P>循环的<TTCLASS="FILENAME">stdout</TT>可以<AHREF="io-redirection.html#IOREDIRREF">重定向</A>到文件中, 			我们对上边的例子做了一点修改. </P><DIVCLASS="EXAMPLE"><HR><ANAME="SYMLINKS2"></A><P><B>例子 10-11. 将目录中所有符号链接文件的名字保存到一个文件中</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;# symlinks.sh: 列出目录中所有的符号链接文件.  3&nbsp;  4&nbsp;OUTFILE=symlinks.list                         # 保存符号链接文件名的文件  5&nbsp;  6&nbsp;directory=${1-`pwd`}  7&nbsp;#  如果没有其他特殊的指定,  8&nbsp;#+ 默认为当前工作目录.  9&nbsp; 10&nbsp; 11&nbsp;echo "symbolic links in directory \"$directory\"" &#62; "$OUTFILE" 12&nbsp;echo "---------------------------" &#62;&#62; "$OUTFILE" 13&nbsp; 14&nbsp;for file in "$( find $directory -type l )"    # -type l = 符号链接 15&nbsp;do 16&nbsp;  echo "$file" 17&nbsp;done | sort &#62;&#62; "$OUTFILE"                     # 循环的stdout 18&nbsp;#           ^^^^^^^^^^^^^                       重定向到一个文件中. 19&nbsp; 20&nbsp;exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><P>有一种非常像C语言<ICLASS="FIRSTTERM">for循环</I>的语法形式. 	     需要使用(()).</P><DIVCLASS="EXAMPLE"><HR><ANAME="FORLOOPC"></A><P><B>例子 10-12. 一个C风格的<BCLASS="COMMAND">for</B>循环</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;# 两种循环到10的方法.  3&nbsp;  4&nbsp;echo  5&nbsp;  6&nbsp;# 标准语法.  7&nbsp;for a in 1 2 3 4 5 6 7 8 9 10  8&nbsp;do  9&nbsp;  echo -n "$a " 10&nbsp;done   11&nbsp; 12&nbsp;echo; echo 13&nbsp; 14&nbsp;# +==========================================+ 15&nbsp; 16&nbsp;# 现在, 让我们用C风格语法来做相同的事情. 17&nbsp; 18&nbsp;LIMIT=10 19&nbsp; 20&nbsp;for ((a=1; a &#60;= LIMIT ; a++))  # 双圆括号, 并且"LIMIT"变量前面没有"$". 21&nbsp;do 22&nbsp;  echo -n "$a " 23&nbsp;done                           # 这是一个借用'ksh93'的结构. 24&nbsp; 25&nbsp;echo; echo 26&nbsp; 27&nbsp;# +=========================================================================+ 28&nbsp; 29&nbsp;# 让我们使用C语言的"逗号操作符", 来同时增加两个变量的值.  30&nbsp; 31&nbsp;for ((a=1, b=1; a &#60;= LIMIT ; a++, b++))  # 逗号将同时进行两条操作. 32&nbsp;do 33&nbsp;  echo -n "$a-$b " 34&nbsp;done 35&nbsp; 36&nbsp;echo; echo 37&nbsp; 38&nbsp;exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><P>参考<AHREF="arrays.html#QFUNCTION">例子 26-15</A>, <AHREF="arrays.html#TWODIM">例子 26-16</A>, 和<AHREF="contributed-scripts.html#COLLATZ">例子 A-6</A>.</P><P>---</P><P>现在, 让我们来看一个<SPANCLASS="QUOTE">"现实生活"</SPAN>中使用<ICLASS="FIRSTTERM">for循环</I>的例子. </P><DIVCLASS="EXAMPLE"><HR><ANAME="EX24"></A><P><B>例子 10-13. 在batch mode中使用<BCLASS="COMMAND">efax</B></B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;# Faxing (前提是'fax'必须已经安装好).  3&nbsp;  4&nbsp;EXPECTED_ARGS=2  5&nbsp;E_BADARGS=65  6&nbsp;  7&nbsp;if [ $# -ne $EXPECTED_ARGS ]  8&nbsp;# 检查命令行参数的个数是否正确.  9&nbsp;then 10&nbsp;   echo "Usage: `basename $0` phone# text-file" 11&nbsp;   exit $E_BADARGS 12&nbsp;fi 13&nbsp; 14&nbsp; 15&nbsp;if [ ! -f "$2" ] 16&nbsp;then 17&nbsp;  echo "File $2 is not a text file" 18&nbsp;  exit $E_BADARGS 19&nbsp;fi 20&nbsp;   21&nbsp; 22&nbsp;fax make $2              # 从纯文本文件中创建传真格式的文件. 23&nbsp; 24&nbsp;for file in $(ls $2.0*)  # 连接转换过的文件. 25&nbsp;                         # 在变量列表中使用通配符. 26&nbsp;do 27&nbsp;  fil="$fil $file" 28&nbsp;done   29&nbsp; 30&nbsp;efax -d /dev/ttyS3 -o1 -t "T$1" $fil   # 干活的地方. 31&nbsp; 32&nbsp; 33&nbsp;# S.C. 指出, 通过下边的命令可以省去for循环. 34&nbsp;#    efax -d /dev/ttyS3 -o1 -t "T$1" $2.0* 35&nbsp;# 但这并不十分具有讲解意义[嘿嘿]. 36&nbsp; 37&nbsp;exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV></DD><DT><ANAME="WHILELOOPREF"></A><BCLASS="COMMAND">while</B></DT><DD><P>这种结构在循环的开头判断条件是否满足, 	      如果条件一直满足, 那么就一直循环下去	      (返回<SPANCLASS="RETURNVALUE">0</SPAN>作为<AHREF="exit-status.html#EXITSTATUSREF">退出状态码</A>). 		  与<AHREF="loops1.html#FORLOOPREF1">for循环</A>的区别是,		  <ICLASS="FIRSTTERM">while循环</I>更适合在循环次数未知的情况下使用. 	  </P><P><P><BCLASS="COMMAND">while</B>  [<TTCLASS="REPLACEABLE"><I>condition</I></TT>]<BR>  do <BR>  <TTCLASS="REPLACEABLE"><I>燾ommand</I></TT>... <BR>  done </P></P><P><AHREF="loops1.html#NEEDSEMICOLON">与<ICLASS="FIRSTTERM">for循环</I>一样</A>,	      如果想把<ICLASS="FIRSTTERM">do</I>和条件判断放到同一行上的话, 	      还是需要一个分号.</P><P><P><BCLASS="COMMAND">while</B>  [<TTCLASS="REPLACEABLE"><I>condition</I></TT>]  ;   do </P></P><P>需要注意一下某种特定的<ICLASS="FIRSTTERM">while循环</I>, 			  比如<AHREF="internal.html#GETOPTSX">getopts结构</A>, 			  好像和这里所介绍的模版有点脱节. </P><DIVCLASS="EXAMPLE"><HR><ANAME="EX25"></A><P><B>例子 10-14. 简单的<BCLASS="COMMAND">while</B>循环</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;  3&nbsp;var0=0  4&nbsp;LIMIT=10  5&nbsp;  6&nbsp;while [ "$var0" -lt "$LIMIT" ]  7&nbsp;do  8&nbsp;  echo -n "$var0 "        # -n 将会阻止产生新行.   9&nbsp;  #             ^           空格, 数字之间的分隔. 10&nbsp; 11&nbsp;  var0=`expr $var0 + 1`   # var0=$(($var0+1))  也可以. 12&nbsp;                          # var0=$((var0 + 1)) 也可以. 13&nbsp;                          # let "var0 += 1"    也可以. 14&nbsp;done                      # 使用其他的方法也行. 15&nbsp; 16&nbsp;echo 17&nbsp; 18&nbsp;exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="EXAMPLE"><HR><ANAME="EX26"></A><P><B>例子 10-15. 另一个<BCLASS="COMMAND">while</B>循环</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;  3&nbsp;echo  4&nbsp;                               # 等价于:  5&nbsp;while [ "$var1" != "end" ]     # while test "$var1" != "end"  6&nbsp;do  7&nbsp;  echo "Input variable #1 (end to exit) "  8&nbsp;  read var1                    # 为什么不使用'read $var1'?  9&nbsp;  echo "variable #1 = $var1"   # 因为包含"#", 所以需要"" 10&nbsp;  # 如果输入为'end', 那么就在这里echo. 11&nbsp;  # 不在这里判断结束, 在循环顶判断. 12&nbsp;  echo 13&nbsp;done   14&nbsp; 15&nbsp;exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><P>一个<ICLASS="FIRSTTERM">while循环</I>可以有多个判断条件. 			但是只有最后一个才能够决定是否能够退出循环.	      然而这里需要一种有点特殊的循环语法.	      </P><DIVCLASS="EXAMPLE"><HR><ANAME="EX26A"></A><P><B>例子 10-16. 多条件的<BCLASS="COMMAND">while</B>循环</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;  3&nbsp;var1=unset  4&nbsp;previous=$var1  5&nbsp;  6&nbsp;while echo "previous-variable = $previous"  7&nbsp;      echo  8&nbsp;      previous=$var1  9&nbsp;      [ "$var1" != end ] # 纪录之前的$var1. 10&nbsp;      # 这个"while"中有4个条件, 但是只有最后一个能够控制循环. 11&nbsp;      # *最后*的退出状态就是由这最后一个条件来决定.  12&nbsp;do 13&nbsp;echo "Input variable #1 (end to exit) " 14&nbsp;  read var1 15&nbsp;  echo "variable #1 = $var1" 16&nbsp;done   17&nbsp; 18&nbsp;# 尝试理解这个脚本的运行过程. 19&nbsp;# 这里还是有点小技巧的. 20&nbsp; 21&nbsp;exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><P>与<ICLASS="FIRSTTERM">for循环</I>一样,			<ICLASS="FIRSTTERM">while循环</I>也可以通过(())来使用C风格的语法. 			(参考<AHREF="dblparens.html#CVARS">例子 9-31</A>).</P><DIVCLASS="EXAMPLE"><HR><ANAME="WHLOOPC"></A><P><B>例子 10-17. C风格的<BCLASS="COMMAND">while</B>循环</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;# wh-loopc.sh: 循环10次的"while"循环.  3&nbsp;  4&nbsp;LIMIT=10  5&nbsp;a=1  6&nbsp;  7&nbsp;while [ "$a" -le $LIMIT ]  8&nbsp;do  9&nbsp;  echo -n "$a " 10&nbsp;  let "a+=1" 11&nbsp;done           # 到目前为止都没有什么令人惊奇的地方. 12&nbsp; 13&nbsp;echo; echo 14&nbsp; 15&nbsp;# +=================================================================+ 16&nbsp; 17&nbsp;# 现在, 重复C风格的语法. 18&nbsp; 19&nbsp;((a = 1))      # a=1 20&nbsp;# 双圆括号允许赋值两边的空格, 就像C语言一样. 21&nbsp; 22&nbsp;while (( a &#60;= LIMIT ))   # 双圆括号, 变量前边没有"$". 23&nbsp;do 24&nbsp;  echo -n "$a " 25&nbsp;  ((a += 1))   # let "a+=1" 26&nbsp;  # Yes, 看到了吧. 27&nbsp;  # 双圆括号允许像C风格的语法一样增加变量的值. 28&nbsp;done 29&nbsp; 30&nbsp;echo 31&nbsp; 32&nbsp;# 现在, C程序员可以在Bash中找到回家的感觉了吧. 33&nbsp; 34&nbsp;exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="NOTE"><P></P><TABLECLASS="NOTE"WIDTH="90%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="./images/note.gif"HSPACE="5"ALT="Note"></TD><TDALIGN="LEFT"VALIGN="TOP"><P><ICLASS="FIRSTTERM">while循环</I>的<TTCLASS="FILENAME">stdin</TT>可以使用<SPANCLASS="TOKEN">&#60;</SPAN>来<AHREF="redircb.html#REDIRREF">重定向到一个文件</A>. </P><P><ICLASS="FIRSTTERM">while循环</I>的<TTCLASS="FILENAME">stdin</TT>支持<AHREF="internal.html#READPIPEREF">管道</A>.</P></TD></TR></TABLE></DIV></DD><DT><ANAME="UNTILLOOPREF"></A><BCLASS="COMMAND">until</B></DT><DD><P>这个结构在循环的顶部判断条件, 并且如果条件一直为false, 那么就一直循环下去.	      (与<ICLASS="FIRSTTERM">while循环</I>相反).</P><P><P><BCLASS="COMMAND">until</B>  [<TTCLASS="REPLACEABLE"><I>condition-is-true</I></TT>]<BR>  do <BR>  <TTCLASS="REPLACEABLE"><I>nbsp;command</I></TT>... <BR>  done </P></P><P>注意, <ICLASS="FIRSTTERM">until循环</I>的条件判断在循环的顶部, 	      这与某些编程语言是不同的. </P><P>与<ICLASS="FIRSTTERM">for循环</I>一样,	      如果想把<ICLASS="FIRSTTERM">do</I>和条件判断放在同一行里, 那么就需要使用分号. </P><P><P><BCLASS="COMMAND">until</B>  [<TTCLASS="REPLACEABLE"><I>condition-is-true</I></TT>]  ;   do </P></P><DIVCLASS="EXAMPLE"><HR><ANAME="EX27"></A><P><B>例子 10-18. <BCLASS="COMMAND">until</B>循环</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;  3&nbsp;END_CONDITION=end  4&nbsp;  5&nbsp;until [ "$var1" = "$END_CONDITION" ]  6&nbsp;# 在循环的顶部进行条件判断.  7&nbsp;do  8&nbsp;  echo "Input variable #1 "  9&nbsp;  echo "($END_CONDITION to exit)" 10&nbsp;  read var1 11&nbsp;  echo "variable #1 = $var1" 12&nbsp;  echo 13&nbsp;done   14&nbsp; 15&nbsp;exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV></DD></DL></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="loops.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="nestedloops.html"ACCESSKEY="N">下一页</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">循环与分支</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="loops.html"ACCESSKEY="U">上一级</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">嵌套循环</TD></TR></TABLE></DIV></BODY></HTML>

⌨️ 快捷键说明

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