- 浏览: 96752 次
- 性别:
- 来自: 武汉
-
最新评论
<p>Bourne again shell (bash)<br>基本编程
<p><a href="http://www-128.ibm.com/developerworks/cn/linux/shell/bash/bash-1/index.html">http://www-128.ibm.com/dev...</a><br /><a href="http://www-128.ibm.com/developerworks/cn/linux/shell/bash/bash-1/index.html#author1">Daniel Robbins</a><br />总裁兼 CEO, Gentoo Technologies, Inc.<br />2000 年 3 月 </p>
<blockquote><p>通<br>过学习如何使用 bash 脚本语言编程,将使 Linux 的日常交互更有趣和有生产力,同时还可以利用那些已熟悉和喜爱的标准 UNIX<br>概念(如管道和重定向)。在此三部分系列中,Daniel Robbins 将以示例指导您如何用 bash<br>编程。他将讲述非常基本的知识(这使此系列十分适合初学者),并在后续系列中逐步引入更高级特性。</p></blockquote>
<p><br><br>
<p>您可能要问:为什么要学习 Bash<br>编程?好,以下是几条令人信服的理由:</p>
<p><br><br>
<p><a name="N10044">已经在运行它</a><br /><br>如果查看一下,可能会发现:您现在正在运行 bash。因为 bash 是标准<br>Linux shell,并用于各种目的,所以,即使更改了缺省 shell,bash<br>可能 <br> <i>仍</i> 在系统中某处运行。因为 bash 已在运行,以后运行的任何<br>bash 脚本都天生是有效利用内存的,因为它们与任何已运行的 bash<br>进程共享内存。如果正在运行的工具可以胜任工作,并且做得很好,为什么还要装入一个<br>500K 的解释器?<br> </p>
<p><br><br> <br><br>
<p><a name="N10050">已经在使用它</a><br /><br>不仅在运行 bash,实际上,您每天还在与 bash<br>打交道。它总在那里,因此学习如何最大限度使用它是有意义的。这样做将使您的<br>bash 经验更有趣和有生产力。但是为什么要学习 bash<br><br> <i>编程</i> ?很简单,因为您已在考虑如何运行命令、CPing<br>文件以及管道化和重定向输出。为什么不学习一种语言,以便使用和利用那些已熟悉和喜爱的强大省时的概念?命令<br>shell 开启了 UNIX 系统的潜能,而 bash 正是 <br> <i>这个</i> Linux<br>shell。它是您和机器之间的高级纽带。增长 bash<br>知识吧,这将自动提高您在 Linux 和 UNIX 中的生产力 --<br>就那么简单。<br> </p>
<p><br><br> <br><br>
<p><a name="N1005F">Bash 困惑</a><br /><br>以错误方式学习 bash 令人十分困惑。许多新手输入 "man bash" 来查看<br>bash 帮助页,但只得到非常简单和技术方面的 shell<br>功能性描述。还有人输入 "info bash"(来查看 GNU<br>信息文档),只能得到重新显示的帮助页,或者(如果幸运)略为友好的信息文档。</p>
<p><br><br> <br><br>
<p>尽管这可能使初学者有些失望,但标准 bash<br>文档无法满足所有人的要求,它只适合那些已大体熟悉 shell<br>编程的人。帮助页中确实有很多极好的技术信息,但对初学者的帮助却有限。</p>
<p><br><br>
<p>这就是本系列的目的所在。在本系列中,我将讲述如何实际使用 bash<br>编程概念,以便编写自己的脚本。与技术描述不同,我将以简单的语言为您解释,使您不仅知道事情做什么,还知道应在何时使用。在此三部分系列末尾,您将可以自己编写复杂的<br>bash 脚本,并可以自如地使用 bash 以及通过阅读(和理解)标准 bash<br>文档来补充知识。让我们开始吧。</p>
<p><br><br>
<p><a name="N1006E">环境变量</a><br /><br>在 bash 和几乎所有其它 shell<br>中,用户可以定义环境变量,这些环境变量在以 ASCII<br>字符串存储。环境变量的最便利之处在于:它们是 UNIX<br>进程模型的标准部分。这意味着:环境变量不仅由 shell<br>脚本独用,而且还可以由编译过的标准程序使用。当在 bash<br>中“导出”环境变量时,以后运行的任何程序,不管是不是 shell<br>脚本,都可以读取设置。一个很好的例子是 vipw 命令,它通常允许 root<br>用户编辑系统口令文件。通过将 EDITOR<br>环境变量设置成喜爱的文本编辑器名称,可以配置<br>vipw,使其使用该编辑器,而不使用 vi,如果习惯于 xemacs 而确实不喜欢<br>vi,那么这是很便利的。</p>
<p><br><br> <br><br>
<p>在 bash 中定义环境变量的标准方法是:</p>
<p><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />$ myvar='This is my environment variable!'<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>以上命令定义了一个名为 "myvar" 的环境变量,并包含字符串 "This is<br>my environment variable!"。以上有几点注意事项:第一,在等号 "="<br>的两边没有空格,任何空格将导致错误(试一下看看)。第二个件要注意的事是:虽然在定义一个字时可以省略引号,但是当定义的环境变量值多于一个字时(包含空格或制表键),引号是必须的。</p>
<p><br><br><br />
<table width="30%" cellspacing="0" cellpadding="5" border="1" align="right">
<tbody>
<tr>
<td><br><br>
<p><a name="sidebar"><b>引用细节</b></a><br /><br>有关如何在 bash 中使用引号的非常详尽的信息,请参阅 bash<br>帮助页面中的“引用”一节。特殊字符序列由其它值“扩展”(替换)确实使<br>bash 中字符串的处理变得复杂。本系列将只讲述最常用的引用功能。<br></p>
<p><br><br> <br><br> </td>
</tr>
</tbody>
</table>
</p>
<p><br><br>
<p><br>第三,虽然通常可以用双引号来替代单引号,但在上例中,这样做会导致错误。为什么呢?因为使用单引号禁用了称为扩展的<br>bash 特性,其中,特殊字符和字符系列由值替换。例如,"!"<br>字符是历史扩展字符,bash<br>通常将其替换为前面输入的命令。(本系列文章中将不讲述历史扩展,因为它在<br>bash 编程中不常用。有关历史扩展的详细信息,请参阅 bash<br>帮助页中的“历史扩展”一节。)尽管这个类似于宏的功能很便利,但我们现在只想在环境变量后面加上一个简单的感叹号,而不是宏。</p>
<p><br><br>
<p>现在,让我们看一下如何实际使用环境变量。这有一个例子:</p>
<p><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />$ echo $myvar<br />This is my environment variable!<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>通过在环境变量的前面加上一个 $,可以使 bash 用 myvar<br>的值替换它。这在 bash<br>术语中叫做“变量扩展”。但是,这样做将怎样:</p>
<p><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />$ echo foo$myvarbar<br />foo<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>我们希望回显 "fooThis is my environment<br>variable!bar",但却不是这样。错在哪里?简单地说,bash<br>变量扩展设施陷入了困惑。它无法识别要扩展哪一个变量:$m、$my、$myvar<br>、$myvarbar 等等。如何更明确清楚地告述 bash<br>引用哪一个变量?试一下这个:</p>
<p><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />$ echo foo${myvar}bar<br />fooThis is my environment variable!bar<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p><br>如您所见,当环境变量没有与周围文本明显分开时,可以用花括号将它括起。虽然<br>$myvar 可以更快输入,并且在大多数情况下正确工作,但 ${myvar}<br>却能在几乎所有情况下正确通过语法分析。除此之外,二者相同,将在本系列的余下部分看到变量扩展的两种形式。请记住:当环境变量没有用空白(空格或制表键)与周围文本分开时,请使用更明确的花括号形式。</p>
<p><br><br>
<p><br>回想一下,我们还提到过可以“导出”变量。当导出环境变量时,它可以自动地由以后运行的任何脚本或可执行程序环境使用。shell<br>脚本可以使用 shell 的内置环境变量支持“到达”环境变量,而 C<br>程序可以使用 getenv() 函数调用。这里有一些 C<br>代码示例,输入并编译它们 -- 它将帮助我们从 C<br>的角度理解环境变量:</p>
<p><br><br> <a name="N100AB"><b>myvar.c -- 样本环境变量 C 程序</b></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />#include <br />#include <br /><br />int main(void) {<br /> char *myenvvar=getenv("EDITOR");<br /> printf("The editor environment variable is set to %s\n",myenvvar);<br />}<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>将上面的代码保存到文件 myenv.c<br>中,然后发出以下命令进行编译:</p>
<p><br><br> <a name="morecode1"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />$ gcc myenv.c -o myenv<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>现在,目录中将有一个可执行程序,它在运行时将打印 EDITOR<br>环境变量的值(如果有值的话)。这是在我机器上运行时的情况:</p>
<p><br><br> <a name="morecode2"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />$ ./myenv<br />The editor environment variable is set to (null)<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>啊... 因为没有将 EDITOR 环境变量设置成任何值,所以 C<br>程序得到一个空字符串。让我们试着将它设置成特定值:</p>
<p><br><br> <a name="morecode3"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />$ EDITOR=xemacs<br />$ ./myenv<br />The editor environment variable is set to (null)<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>虽然希望 myenv 打印值<br>"xemacs",但是因为还没有导出环境变量,所以它却没有很好地工作。这次让它正确工作:</p>
<p><br><br> <a name="morecode4"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />$ export EDITOR<br />$ ./myenv<br />The editor environment variable is set to xemacs<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>现在,如您亲眼所见:不导出环境变量,另一个进程(在本例中是示例 C<br>程序)就看不到环境变量。顺便提一句,如果愿意,可以在一行定义并导出环境变量,如下所示:</p>
<p><br><br> <a name="morecode5"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />$ export EDITOR=xemacs<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>这与两行版本的效果相同。现在该演示如何使用 unset<br>来除去环境变量:</p>
<p><br><br> <a name="morecode6"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />$ unset EDITOR<br />$ ./myenv<br />The editor environment variable is set to (null)<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br><br />
<table width="30%" cellspacing="0" cellpadding="5" border="1" align="right">
<tbody>
<tr>
<td><br><br>
<p><a name="N100FF"><b>dirname 和 basename</b></a><br /><br>请注意:dirname 和 basename<br>不是磁盘上的文件或目录,它们只是字符串操作命令。<br></p>
<p><br><br> <br><br> </td>
</tr>
</tbody>
</table>
</p>
<p><br><br>
<p><a name="N10109">截断字符串概述</a><br /><br>截断字符串是将初始字符串截断成较小的独立块,它是一般 shell<br>脚本每天执行的任务之一。很多时候,shell<br>脚本需要采用全限定路径,并找到结束的文件或目录。虽然可以用 bash<br>编码实现(而且有趣),但标准 basename UNIX<br>可执行程序可以极好地完成此工作:</p>
<p><br><br> <br><br> <a name="morecode7"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />$ basename /usr/local/share/doc/foo/foo.txt<br />foo.txt<br />$ basename /usr/home/drobbins<br />drobbins<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>Basename 是一个截断字符串的极简便工具。它的相关命令 dirname 返回<br>basename 丢弃的“另”一部分路径。</p>
<p><br><br> <a name="morecode8"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />$ dirname /usr/local/share/doc/foo/foo.txt<br />/usr/local/share/doc/foo<br />$ dirname /usr/home/drobbins/<br />/usr/home<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p><a name="N10127">命令替换</a><br /><br>需要知道一个简便操作:如何创建一个包含可执行命令结果的环境变量。这很容易:</p>
<p><br><br> <br><br> <a name="morecode9"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />$ MYDIR=`dirname /usr/local/share/doc/foo/foo.txt`<br />$ echo $MYDIR<br />/usr/local/share/doc/foo<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p><br>上面所做的称为“命令替换”。此例中有几点需要指出。在第一行,简单地将要执行的命令以 <br> <i><br>反引号</i> 括起。那不是标准的单引号,而是键盘中通常位于 Tab<br>键之上的单引号。可以用 bash 备用命令替换语法来做同样的事:<br> </p>
<p><br><br> <a name="morecode10"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />$ MYDIR=$(dirname /usr/local/share/doc/foo/foo.txt)<br />$ echo $MYDIR<br />/usr/local/share/doc/foo<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>如您所见,bash<br>提供多种方法来执行完全一样的操作。使用命令替换可以将任何命令或命令管道放在<br>` ` 或 $( )<br>之间,并将其分配给环境变量。真方便!下面是一个例子,演示如何在命令替换中使用管道:</p>
<p><br><br> <a name="morecode11"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />MYFILES=$(ls /etc | grep pa)<br />bash-2.03$ echo $MYFILES<br />pam.d passwd<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p><a name="N10154">象专业人员那样截断字符串</a><br /><br>尽管 basename 和 dirname<br>是很好的工具,但有时可能需要执行更高级的字符串“截断”,而不只是标准的路径名操作。当需要更强的说服力时,可以利用<br>bash 内置的变量扩展功能。已经使用了类似于 ${MYVAR}<br>的标准类型的变量扩展。但是 bash<br>自身也可以执行一些便利的字符串截断。看一下这些例子:</p>
<p><br><br> <br><br> <a name="morecode12"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />$ MYVAR=foodforthought.jpg<br />$ echo ${MYVAR##*fo}<br />rthought.jpg<br />$ echo ${MYVAR#*fo}<br />odforthought.jpg<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>在第一个例子中,输入了<br>${MYVAR##*fo}。它的确切含义是什么?基本上,在 ${ }<br>中输入环境变量名称,两个 ##,然后是通配符 ("*fo")。然后,bash 取得<br>MYVAR,找到从字符串 "foodforthought.jpg" 开始处开始、且匹配通配符<br>"*fo"<br>的 <br> <i>最长</i> 子字符串,然后将其从字符串的开始处截去。刚开始理解时会有些困难,为了感受一下这个特殊的<br>"##" 选项如何工作,让我们一步步地看看 bash<br>如何完成这个扩展。首先,它从 "foodforthought.jpg" 的开始处搜索与<br>"*fo" 通配符匹配的子字符串。以下是检查到的子字符串:<br> </p>
<p><br><br> <a name="morecode13"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />f <br />fo MATCHES *fo<br />foo <br />food<br />foodf <br />foodfo MATCHES *fo<br />foodfor<br />foodfort <br />foodforth<br />foodfortho <br />foodforthou<br />foodforthoug<br />foodforthought<br />foodforthought.j<br />foodforthought.jp<br />foodforthought.jpg<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>在搜索了匹配的字符串之后,可以看到 bash<br>找到两个匹配。它选择最长的匹配,从初始字符串的开始处除去,然后返回结果。</p>
<p><br><br>
<p>上面所示的第二个变量扩展形式看起来与第一个相同,但是它只使用一个<br>"#" -- 并且 bash<br>执行 <br> <i>几乎</i> 同样的过程。它查看与第一个例子相同的子字符串系列,但是<br>bash 从初始字符串除去 <br> <i>最短</i> 的匹配,然后返回结果。所以,一查到<br>"fo" 子字符串,它就从字符串中除去 "fo",然后返回<br>"odforthought.jpg"。<br> </p>
<p><br><br>
<p><br>这样说可能会令人十分困惑,下面以一简单方式记住这个功能。当搜索最长匹配时,使用<br>##(因为 ## 比 # 长)。当搜索最短匹配时,使用<br>#。看,不难记吧!等一下,怎样记住应该使用 '#'<br>字符来从字符串开始部分除去?很简单!注意到了吗:在美国键盘上,shift-4<br>是 "$",它是 bash 变量扩展字符。在键盘上,紧靠 "$" 左边的是<br>"#"。这样,可以看到:"#" 位于 "$"<br>的“开始处”,因此(根据我们的记忆法),"#"<br>从字符串的开始处除去字符。您可能要问:如何从字符串末尾除去字符。如果猜到我们使用美国键盘上紧靠<br>"$"<br> <i>右边</i> 的字符<br>("%),那就猜对了。这里有一些简单的例子,解释如何截去字符串的末尾部分:<br> </p>
<p><br><br> <a name="morecode14"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />$ MYFOO="chickensoup.tar.gz"<br />$ echo ${MYFOO%%.*}<br />chickensoup<br />$ echo ${MYFOO%.*}<br />chickensoup.tar<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>正如您所见,除了将匹配通配符从字符串末尾除去之外,% 和 %%<br>变量扩展选项与 # 和 ##<br>的工作方式相同。请注意:如果要从末尾除去特定子字符串,不必使用 "*"<br>字符:</p>
<p><br><br> <a name="morecode15"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />MYFOOD="chickensoup"<br />$ echo ${MYFOOD%%soup}<br />chicken<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>在此例中,使用 "%%" 或 "%"<br>并不重要,因为只能有一个匹配。还要记住:如果忘记了应该使用 "#" 还是<br>"%",则看一下键盘上的 3、4 和 5 键,然后猜出来。</p>
<p><br><br>
<p><br>可以根据特定字符偏移和长度,使用另一种形式的变量扩展,来选择特定子字符串。试着在<br>bash 中输入以下行:</p>
<p><br><br> <a name="morecode16"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />$ EXCLAIM=cowabunga<br />$ echo ${EXCLAIM:0:3}<br />cow<br />$ echo ${EXCLAIM:3:7}<br />abunga<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p><br>这种形式的字符串截断非常简便,只需用冒号分开来指定起始字符和子字符串长度。</p>
<p><br><br>
<p><a name="N101AE">应用字符串截断</a><br /><br>现在我们已经学习了所有截断字符串的知识,下面写一个简单短小的 shell<br>脚本。我们的脚本将接受一个文件作为自变量,然后打印:该文件是否是一个<br>tar 文件。要确定它是否是 tar 文件,将在文件末尾查找模式<br>".tar"。如下所示:</p>
<p><br><br> <br><br> <a name="N101B7"><b>mytar.sh -- 一个简单的脚本</b></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />#!/bin/bash<br /><br />if [ "${1##*.}" = "tar" ]<br />then <br /> echo This appears to be a tarball.<br />else<br /> echo At first glance, this does not appear to be a tarball.<br />fi<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>要运行此脚本,将它输入到文件 mytar.sh 中,然后输入 "chmod 755<br>mytar.sh",生成可执行文件。然后,如下做一下 tar 文件试验:</p>
<p><br><br> <a name="morecode17"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />$ ./mytar.sh thisfile.tar<br />This appears to be a tarball.<br />$ ./mytar.sh thatfile.gz<br />At first glance, this does not appear to be a tarball.<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>好,成功运行,但是不太实用。在使它更实用之前,先看一下上面使用的<br>"if" 语句。语句中使用了一个布尔表达式。在 bash 中,"="<br>比较运算符检查字符串是否相等。在 bash<br>中,所有布尔表达式都用方括号括起。但是布尔表达式实际上测试什么?让我们看一下左边。根据前面所学的字符串截断知识,"${1##*.}"<br>将从环境变量 "1" 包含的字符串开始部分除去最长的 "*."<br>匹配,并返回结果。这将返回文件中最后一个 "."<br>之后的所有部分。显然,如果文件以 ".tar" 结束,结果将是<br>"tar",条件也为真。</p>
<p><br><br>
<p>您可能会想:开始处的 "1" 环境变量是什么。很简单 -- $1<br>是传给脚本的第一个命令行自变量,$2<br>是第二个,以此类推。好,已经回顾了功能,下面来初探 "if" 语句。</p>
<p><br><br>
<p><a name="N101D3">If 语句</a><br /><br>与大多数语言一样,bash<br>有自己的条件形式。在使用时,要遵循以上格式;即,将 "if" 和 "then"<br>放在不同行,并使 "else" 和结束处必需的 "fi"<br>与它们水平对齐。这将使代码易于阅读和调试。除了 "if,else"<br>形式之外,还有其它形式的 "if" 语句:</p>
<p><br><br> <br><br> <a name="morecode18"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />if [ condition ]<br />then <br /> action<br />fi<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>只有当 <br> <code>condition</code> 为真时,该语句才执行操作,否则不执行操作,并继续执行 "fi" 之后的任何行。<br> </p>
<p><br><br> <a name="morecode19"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br />if [ condition ]<br />then <br /> action<br />elif [ condition2 ]<br />then <br /> action2<br />.<br />.<br />.<br />elif [ condition3 ]<br />then <br /><br />else<br /> actionx<br />fi<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>以上 "elif"<br>形式将连续测试每个条件,并执行符合第一个 <br> <i>真</i> 条件的操作。如果没有条件为真,则将执行<br>"else" 操作,如果有一个条件为真,则继续执行整个 "if,elif,else"<br>语句之后的行。<br> </p>
<p><br><br>
<p><a name="N101FB">下一次</a><br /><br>我们已经学习了最基本的 bash<br>功能,现在要加快脚步,准备编写一些实际脚本。在下一篇中,将讲述循环概念、函数、名称空间和其它重要主题。然后,将准备好编写一些更复杂的脚本。在第三篇中,将重点讲述一些非常复杂的脚本和功能,以及几个<br>bash 脚本设计选项。再见!</p>
<p><br><br> <br><br>
<p><a name="resources">参考资料 </a><br><br> </p>
<ul>
<li>您可以参阅本文在 developerWorks 全球站点上的<br> <a href="http://www.ibm.com/developerworks/library/l-bash.html">英文原文</a>.<br> </p>
</li>
<li>访问<br> <a href="http://www.gnu.org/software/bash/bash.html">GNU's<br>bash 主页</a><br><br>
</li>
<li>查看<br> <a href="http://www.gnu.org/manual/bash/index.html">bash<br>online reference manual</a> </li>
</ul>
<p><br><br> <a name="author1"></a><br><br />更多的 bash 基本编程
<p><a href="http://www-128.ibm.com/developerworks/cn/linux/shell/bash/bash-2/index.html#author1">Daniel Robbins</a><br />总裁兼 CEO, Gentoo Technologies, Inc.<br />2000 年 4 月 </p>
<blockquote><p>在前一篇 bash 的介绍性文章中,Daniel Robbins 为您讲解了脚本语言的一些基本元素和使用 bash 的原因。在本文(即第二部分)中,Daniel 继续前一篇的内容,并讲解条件 (if-then) 语句、循环和更多的 bash 基本结构。</p></blockquote>
<p><br><br>
<p>我们先看一下处理命令行自变量的简单技巧,然后再看看 bash<br>基本编程结构。</p>
<p><br><br>
<p><a name="N10048">接收自变量</a><br /><br>在 <br> <a href="http://www-4.ibm.com/software/developerworks/library/bash.html">介绍性文章</a> 中的样本程序中,我们使用环境变量 "$1"<br>来引用第一个命令行自变量。类似地,可以使用 "$2"、"$3"<br>等来引用传递给脚本的第二和第三个自变量。这里有一个例子:<br> </p>
<p><br><br> <br><br> <a name="code1"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br /> #!/usr/bin/env bash<br /> <br /> echo name of script is $0<br /> echo first argument is $1<br /> echo second argument is $2<br /> echo seventeenth argument is $17<br /> echo number of arguments is $#<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>除以下两个细节之外,此例无需说明。第一,"$0"<br>将扩展成从命令行调用的脚本名称,"$#"<br>将扩展成传递给脚本的自变量数目。试验以上脚本,通过传递不同类型的命令行自变量来了解其工作原理。</p>
<p><br><br>
<p>有时需要一次引用<br> <i>所有</i> 命令行自变量。针对这种用途,bash<br>实现了变量 "$@",它扩展成所有用空格分开的命令行参数。在本文稍后的<br>"for" 循环部分中,您将看到使用该变量的例子。<br> </p>
<p><br><br>
<p><a name="N10067">Bash 编程结构</a><br /><br>如果您曾用过如 C、Pascal、Python 或 Perl<br>那样的过程语言编程,则一定熟悉 "if" 语句和 "for"<br>循环那样的标准编程结构。对于这些标准结构的大多数,Bash<br>有自己的版本。在下几节中,将介绍几种 bash<br>结构,并演示这些结构和您已经熟悉的其它编程语言中结构的差异。如果以前编程不多,也不必担心。我提供了足够的信息和示例,使您可以跟上本文的进度。</p>
<p><br><br> <br><br>
<p><a name="N10070">方便的条件语句</a><br /><br>如果您曾用 C<br>编写过与文件相关的代码,则应该知道:要比较特定文件是否比另一个文件新需要大量工作。那是因为<br>C 没有任何内置语法来进行这种比较,必须使用两个 stat() 调用和两个<br>stat 结构来进行手工比较。相反,bash<br>内置了标准文件比较运算符,因此,确定“/tmp/myfile<br>是否可读”与查看“$myvar 是否大于 4”一样容易。</p>
<p><br><br> <br><br>
<p>下表列出最常用的 bash<br>比较运算符。同时还有如何正确使用每一选项的示例。示例要跟在 "if"<br>之后。例如:</p>
<p><br><br> <a name="code2"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br /> if [ -z "$myvar" ]<br />then <br /> echo "myvar is not defined"<br />fi<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br> <br><br><br />
<table cellspacing="0" cellpadding="3" border="0">
<tbody>
<tr valign="top" bgcolor="#0033cc">
<td><br> <b>运算符</b><br> </td>
<td><br> <b>描述</b><br> </td>
<td><br> <b>示例</b><br> </td>
</tr>
<tr valign="top" bgcolor="#888888">
<td colspan="3"><br> <b><br> 文件比较运算符<br> </b><br> </td>
</tr>
<tr valign="top" bgcolor="#eeeeee">
<td>-e<br> <i>filename</i><br><br> </td>
<td>如果<br> <i>filename</i>存在,则为真<br> </td>
<td>[ -e /var/log/syslog ]</td>
</tr>
<tr valign="top" bgcolor="#eeeeee">
<td>-d<br> <i>filename</i><br><br> </td>
<td>如果<br> <i>filename</i>为目录,则为真<br> </td>
<td>[ -d /tmp/mydir ]</td>
</tr>
<tr valign="top" bgcolor="#eeeeee">
<td>-f<br> <i>filename</i><br><br> </td>
<td>如果<br> <i>filename</i>为常规文件,则为真<br> </td>
<td>[ -f /usr/bin/grep ]</td>
</tr>
<tr valign="top" bgcolor="#eeeeee">
<td>-L<br> <i>filename</i><br><br> </td>
<td>如果<br> <i>filename</i>为符号链接,则为真<br> </td>
<td>[ -L /usr/bin/grep ]</td>
</tr>
<tr valign="top" bgcolor="#eeeeee">
<td>-r<br> <i>filename</i><br><br> </td>
<td>如果<br> <i>filename</i>可读,则为真<br> </td>
<td>[ -r /var/log/syslog ]</td>
</tr>
<tr valign="top" bgcolor="#eeeeee">
<td>-w<br> <i>filename</i><br><br> </td>
<td>如果<br> <i>filename</i>可写,则为真<br> </td>
<td>[ -w /var/mytmp.txt ]</td>
</tr>
<tr valign="top" bgcolor="#eeeeee">
<td>-x<br> <i>filename</i><br><br> </td>
<td>如果<br> <i>filename</i>可执行,则为真<br> </td>
<td>[ -L /usr/bin/grep ]</td>
</tr>
<tr valign="top" bgcolor="#eeeeee">
<td><br><br> <i>filename1</i>-nt<br> <i>filename2</i><br><br> </td>
<td>如果<br> <i>filename1</i>比<br> <i>filename2</i>新,则为真<br> </td>
<td>[ /tmp/install/etc/services -nt /etc/services ]</td>
</tr>
<tr valign="top" bgcolor="#eeeeee">
<td><br><br> <i>filename1</i>-ot<br> <i>filename2</i><br><br> </td>
<td>如果<br> <i>filename1</i>比<br> <i>filename2</i>旧,则为真<br> </td>
<td>[ /boot/bzImage -ot arch/i386/boot/bzImage ]</td>
</tr>
<tr valign="top" bgcolor="#888888">
<td colspan="3"><br> <b><br> 字符串比较运算符<br> </b>(请注意引号的使用,这是防止空格扰乱代码的好方法)<br> </td>
</tr>
<tr valign="top" bgcolor="#eeeeee">
<td>-z<br> <i>string</i><br><br> </td>
<td>如果<br> <i>string</i>长度为零,则为真<br> </td>
<td>[ -z "$myvar" ]</td>
</tr>
<tr valign="top" bgcolor="#eeeeee">
<td>-n<br> <i>string</i><br><br> </td>
<td>如果<br> <i>string</i>长度非零,则为真<br> </td>
<td>[ -n "$myvar" ]</td>
</tr>
<tr valign="top" bgcolor="#eeeeee">
<td><br><br> <i>string1</i>=<br> <i>string2</i><br><br> </td>
<td>如果<br> <i>string1</i>与<br> <i>string2</i>相同,则为真<br> </td>
<td>[ "$myvar" = "one two three" ]</td>
</tr>
<tr valign="top" bgcolor="#eeeeee">
<td><br><br> <i>string1</i>!=<br> <i>string2</i><br><br> </td>
<td>如果<br> <i>string1</i>与<br> <i>string2</i>不同,则为真<br> </td>
<td>[ "$myvar" != "one two three" ]</td>
</tr>
<tr valign="top" bgcolor="#888888">
<td colspan="3"><br> <b><br> 算术比较运算符<br> </b><br> </td>
</tr>
<tr valign="top" bgcolor="#eeeeee">
<td><br><br> <i>num1</i>-eq<br> <i>num2</i><br><br> </td>
<td>等于</td>
<td>[ 3 -eq $mynum ]</td>
</tr>
<tr valign="top" bgcolor="#eeeeee">
<td><br><br> <i>num1</i>-ne<br> <i>num2</i><br><br> </td>
<td>不等于</td>
<td>[ 3 -ne $mynum ]</td>
</tr>
<tr valign="top" bgcolor="#eeeeee">
<td><br><br> <i>num1</i>-lt<br> <i>num2</i><br><br> </td>
<td>小于</td>
<td>[ 3 -lt $mynum ]</td>
</tr>
<tr valign="top" bgcolor="#eeeeee">
<td><br><br> <i>num1</i>-le<br> <i>num2</i><br><br> </td>
<td>小于或等于</td>
<td>[ 3 -le $mynum ]</td>
</tr>
<tr valign="top" bgcolor="#eeeeee">
<td><br><br> <i>num1</i>-gt<br> <i>num2</i><br><br> </td>
<td>大于</td>
<td>[ 3 -gt $mynum ]</td>
</tr>
<tr valign="top" bgcolor="#eeeeee">
<td><br><br> <i>num1</i>-ge<br> <i>num2</i><br><br> </td>
<td>大于或等于</td>
<td>[ 3 -ge $mynum ]</td>
</tr>
</tbody>
</table>
<p><br><br>
<p><br>有时,有几种不同方法来进行特定比较。例如,以下两个代码段的功能相同:</p>
<p><br><br> <a name="code3"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br /> if [ "$myvar" -eq 3 ]<br />then <br /> echo "myvar equals 3"<br />fi<br /> <br /> <br /> if [ "$myvar" = "3" ]<br />then <br /> echo "myvar equals 3"<br />fi<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p><br>上面两个比较执行相同的功能,但是第一个使用算术比较运算符,而第二个使用字符串比较运算符。</p>
<p><br><br>
<p><a name="N1026B">字符串比较说明</a><br /><br>大多数时候,虽然可以不使用括起字符串和字符串变量的双引号,但这并不是好主意。为什么呢?因为如果环境变量中恰巧有一个空格或制表键,bash<br>将无法分辨,从而无法正常工作。这里有一个错误的比较示例:</p>
<p><br><br> <br><br> <a name="code4"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br /> if [ $myvar = "foo bar oni" ]<br />then <br /> echo "yes"<br />fi<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>在上例中,如果 myvar 等于<br>"foo",则代码将按预想工作,不进行打印。但是,如果 myvar 等于 "foo<br>bar oni",则代码将因以下错误失败:</p>
<p><br><br> <a name="code5"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br /> [: too many arguments<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>在这种情况下,"$myvar"(等于 "foo bar oni")中的空格迷惑了<br>bash。bash 扩展 "$myvar" 之后,代码如下:</p>
<p><br><br> <a name="code6"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br /> [ foo bar oni = "foo bar oni" ]<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>因为环境变量没放在双引号中,所以 bash<br>认为方括号中的自变量过多。可以用双引号将字符串自变量括起来消除该问题。请记住,如果养成将所有字符串自变量用双引号括起的习惯,将除去很多类似的编程错误。"foo<br>bar oni" 比较 <br> <i>应该</i>写成:<br> </p>
<p><br><br> <a name="code7"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br /> if [ "$myvar" = "foo bar oni" ]<br />then <br /> echo "yes"<br />fi<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br><br />
<table width="30%" cellspacing="0" cellpadding="5" border="1" align="right">
<tbody>
<tr>
<td><br><br>
<p><a name="N102A6"><b>更多引用细节</b></a><br /><br>如果要扩展环境变量,则必须将它们用 <br> <i>双引号</i>、而不是单引号括起。单引号<br> <i><br>禁用</i> 变量(和历史)扩展。<br><br> </p>
<p><br><br> <br><br> </td>
</tr>
</tbody>
</table>
</p>
<p><br><br>
<p>以上代码将按预想工作,而不会有任何令人不快的意外出现。</p>
<p><br><br>
<p><a name="N102B9">循环结构:"for"</a><br /><br>好了,已经讲了条件语句,下面该探索 bash 循环结构了。我们将从标准的<br>"for" 循环开始。这里有一个简单的例子:</p>
<p><br><br> <br><br> <a name="code8"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br /> <br /> #!/usr/bin/env bash<br /> <br /> for x in one two three four<br /> do<br /> echo number $x<br /> done<br /> <br /> <br /> <font color="red">输出:</font><br /> <br /> number one<br /> number two <br /> number three <br /> number four<br /><br /> </code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>发生了什么?"for" 循环中的 "for x" 部分定义了一个名为 "$x"<br>的新环境变量(也称为循环控制变量),它的值被依次设置为<br>"one"、"two"、"three" 和<br>"four"。每一次赋值之后,执行一次循环体("do" 和 "done"<br>之间的代码)。在循环体内,象其它环境变量一样,使用标准的变量扩展语法来引用循环控制变量<br>"$x"。还要注意,"for" 循环总是接收 "in"<br>语句之后的某种类型的字列表。在本例中,指定了四个英语单词,但是字列表也可以引用磁盘上的文件,甚至文件通配符。看看下面的例子,该例演示如何使用标准<br>shell 通配符:</p>
<p><br><br> <a name="code9"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br /> #!/usr/bin/env bash<br /> <br /> for myfile in /etc/r*<br /> do<br /> if [ -d "$myfile" ] <br />then <br /> echo "$myfile (dir)"<br />else<br /> echo "$myfile"<br />fi<br /> done<br /> <br /> <br /> <font color="red">输出:</font><br /> <br /> /etc/rc.d (dir)<br /> /etc/resolv.conf<br /> /etc/resolv.conf~<br /> /etc/rpc <br /><br /> </code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>以上代码列出在 /etc 中每个以 "r" 开头的文件。要做到这点,bash<br>在执行循环之前首先取得通配符 /etc/r*,然后扩展它,用字符串<br>/etc/rc.d /etc/resolv.conf /etc/resolv.conf~ /etc/rpc<br>替换。一旦进入循环,根据 myfile 是否为目录,"-d"<br>条件运算符用来执行两个不同操作。如果是目录,则将 "(dir)"<br>附加到输出行。</p>
<p><br><br>
<p>还可以在字列表中使用多个通配符、甚至是环境变量:</p>
<p><br><br> <a name="code10"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br /> <br /> for x in /etc/r--? /var/lo* /home/drobbins/mystuff/* /tmp/${MYPATH}/*<br /> do<br /> cp $x /mnt/mydir<br /> done<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>Bash<br>将在所有正确位置上执行通配符和环境变量扩展,并可能创建一个非常长的字列表。</p>
<p><br><br>
<p><br>虽然所有通配符扩展示例使用了 <br> <i>绝对</i>路径,但也可以使用相对路径,如下所示:<br> </p>
<p><br><br> <a name="code11"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br /> <br /> for x in ../* mystuff/*<br /> do<br /> echo $x is a silly file<br /> done<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>在上例中,bash<br>相对于当前工作目录执行通配符扩展,就象在命令行中使用相对路径一样。研究一下通配符扩展。您将注意到,如果在通配符中使用绝对路径,bash<br>将通配符扩展成一个绝对路径列表。否则,bash<br>将在后面的字列表中使用相对路径。如果只引用当前工作目录中的文件(例如,如果输入<br>"for x in<br>*"),则产生的文件列表将没有路径信息的前缀。请记住,可以使用<br>"basename" 可执行程序来除去前面的路径信息,如下所示:</p>
<p><br><br> <a name="code12"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br /> <br /> for x in /var/log/*<br /> do<br /> echo `basename $x` is a file living in /var/log<br /> done<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p><br>当然,在脚本的命令行自变量上执行循环通常很方便。这里有一个如何使用本文开始提到的<br>"$@" 变量的例子:</p>
<p><br><br> <a name="code13"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br /> <br /> #!/usr/bin/env bash<br /> <br /> for thing in "$@"<br /> do<br /> echo you typed ${thing}.<br /> done<br /> <br /> <br /> <font color="red">输出:</font><br /> <br /> $ allargs hello there you silly<br /> you typed hello.<br /> you typed there.<br /> you typed you.<br /> you typed silly.<br /><br /> </code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p><a name="N1031C">Shell 算术</a><br /><br>在学习另一类型的循环结构之前,最好先熟悉如何执行 shell<br>算术。是的,确实如此:可以使用 shell<br>结构来执行简单的整数运算。只需将特定的算术表达式用 "$((" 和 "))"<br>括起,bash 就可以计算表达式。这里有一些例子:</p>
<p><br><br> <br><br> <a name="newcode1"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br /> $ echo $(( 100 / 3 ))<br /> 33<br /> $ myvar="56"<br /> $ echo $(( $myvar + 12 ))<br /> 68<br /> $ echo $(( $myvar - $myvar ))<br />0 $ myvar=$(( $myvar + 1 ))<br />$ echo $myvar<br /> 57<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p><a name="N1032E">更多的循环结构:"while" 和<br>"until"</a><br /><br>只要特定条件为真,"while" 语句就会执行,其格式如下:</p>
<p><br><br> <br><br> <a name="newcode2"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br /> while [ condition ]<br /> do<br /> statements<br /> done<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>通常使用 "While" 语句来循环一定次数,比如,下例将循环 10 次:</p>
<p><br><br> <a name="newcode3"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br /> myvar=0<br /> while [ $myvar -ne 10 ]<br /> do<br /> echo $myvar<br /> myvar=$(( $myvar + 1 ))<br /> done<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p><br>可以看到,上例使用了算术表达式来使条件最终为假,并导致循环终止。</p>
<p><br><br>
<p>"Until" 语句提供了与 "while"<br>语句相反的功能:只要特定条件为 <br> <i>假</i> ,它们就重复。下面是一个与前面的<br>"while" 循环具有同等功能的 "until" 循环:<br> </p>
<p><br><br> <a name="newcode4"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br /> myvar=0<br /> until [ $myvar -eq 10 ]<br /> do<br /> echo $myvar<br /> myvar=$(( $myvar + 1 ))<br /> done<br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p><a name="N1035E">Case 语句</a><br /><br>Case 语句是另一种便利的条件结构。这里有一个示例片段:</p>
<p><br><br> <br><br> <a name="code14"></a><br /><br> <br><br />
<table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc">
<tbody>
<tr>
<td>
<pre><code><br /> <br /> case "${x##*.}" in<br /> gz)<br /> gzunpack ${SROOT}/${x}<br /> ;;<br /> bz2)<br /> bz2unpack ${SROOT}/${x}<br /> ;;<br /> *)<br /> echo "Archive format not recognized."<br /> exit<br /> ;;<br /> esac <br /></code></pre></td>
</tr>
</tbody>
</table>
<p> <br><br>
<p>在上例中,bash 首先扩展 "${x##*.}"。在代码中,"$x"<br>是文件的名称,"${x##.*}"<br>除去文件中最后句点后文本之外的所有文本。然后,bash 将产生的字符串与<br>")" 左边列出的值做比较。在本例中,"${x##.*}" 先与 "gz" 比较,然后是<br>"bz2",最后是 "*"。如果 "${x##.*}"<br>与这些字符串或模式中的任何一个匹配,则执行紧接 ")" 之后的行,直到<br>";;" 为止,然后 bash 继续执行结束符 "esac"<br>之后的行。如果不匹配任何模式或字符串,则不执行任何代码行,在这个特殊的代码片段中,至少要执行一个代码块,因为任何不与<br>"
评论
2 楼
lawever
2008-06-07
http://www-128.ibm.com/developerworks/cn/linux/shell/bash/bash-1/index.html
1 楼
pig345
2008-05-26
这篇文章有特点,应该是在考察开发者对html的熟知程度。
(可以预见,只有极少数人能在脑袋中直接渲染html)
(可以预见,只有极少数人能在脑袋中直接渲染html)
相关推荐
### Python爬虫Scrapy实例详解 #### 创建Scrapy项目 Scrapy是一款强大的开源网页抓取框架,被广泛应用于数据采集领域。本文档旨在通过一个具体的示例,详细讲解如何使用Scrapy创建并运行一个基本的爬虫项目。 ###...
```bash pip install openpyxl pandas ``` ##### 3. 数据准备 入库单据数据通常包含商品名称、数量、单价等信息。这些数据可以以列表、字典或其他形式存储。例如: ```python inbound_data = [ {"product_name":...
```bash pip install qrcode[pil] ``` 安装完成后,我们可以编写Python代码来生成一个基本的二维码: ```python import qrcode # 生成二维码 qr = qrcode.QRCode( version=1, error_correction=qrcode....
在本篇内容中,我们将基于提供的标题“py源码实例excel处理实例求和结果写入单元格”以及描述“py源码实例自动办公excel处理实例(求和结果写入单元格)提取方式是百度网盘分享地址”,来深入探讨Python在处理Excel...
```bash pip install pandas openpyxl ``` 3. **准备Excel文件**: - 准备一份包含学生成绩信息的Excel文件,其中至少包括“姓名”、“科目1分数”、“科目2分数”等列,并且有一列用于计算总分。 #### 二、...
```bash pip install wxpy pandas matplotlib seaborn ``` #### 3.2 登录微信 使用wxpy库可以轻松实现微信的自动化操作,包括登录: ```python from wxpy import Bot bot = Bot() ``` #### 3.3 获取好友列表 ```...
### Python-xlwings 英文手册及实例解析 #### Python-xlwings简介 Python-xlwings 是一个开源库,主要用于实现Python与Excel之间的交互。它为用户提供了简单易用的接口,可以方便地读取、修改Excel文件以及利用...
### py源码实例:使用xlutils进行Excel格式设置 #### 一、xlutils库简介 在Python编程语言中,处理Excel文件是一项常见的需求,尤其是在数据分析、报表自动化等领域。`xlutils`是一个基于`xlrd`和`xlwt`的Python库...
```bash pip install pandas ``` #### 2.3 安装Openpyxl库 Openpyxl是一个用于读取和写入Excel 2010 xlsx/xlsm/xltx/xltm文件的库。同样,也可以通过pip命令进行安装: ```bash pip install openpyxl ``` ### 三、...
在本案例中,提供的百度网盘分享链接指向了一个包含 Python 源码实例的文件夹,该实例演示了如何进行 Word 文档的格式套用。 #### 3.2 如何获取分享链接中的文件 要从百度网盘分享链接中下载文件,通常需要输入...
```bash pip install python-pptx ``` 2. **读取PPT文件**: ```python from pptx import Presentation # 加载PPT文件 prs = Presentation('example.pptx') ``` 3. **遍历幻灯片提取文本**: ```python ...
### py源码实例:在PPT中写入文字 #### 背景介绍 随着Python在办公自动化领域的广泛应用,利用Python脚本自动生成或编辑PPT文档的需求日益增多。通过Python编写脚本来处理PPT文档不仅可以提高工作效率,还能实现...
### py源码实例:Excel-xlrd读-xlwt写 #### 知识点一:xlrd与xlwt模块介绍 在Python编程语言中,处理Excel文件(.xls格式)时经常用到两个强大的库:`xlrd` 和 `xlwt`。`xlrd` 主要用于读取Excel文件中的数据,而 ...
### py源码实例自动办公批量生成PPT版荣誉证书 #### 概述 在现代办公环境中,自动化工具的使用能够极大地提高工作效率并减少重复性劳动。本案例介绍了一个使用Python编写的源代码示例,该示例能够实现批量生成PPT...
### py源码实例用Python在Excel中查找并替换数据 #### 知识点解析 ##### 一、Python处理Excel文件的基础知识 1. **库的选择**:在Python中处理Excel文件,常用到的库有`pandas`和`openpyxl`。 - **pandas**:...
```bash pip install openpyxl ``` 2. **读取Excel文件** 使用`openpyxl`加载Excel文件并读取数据: ```python from openpyxl import load_workbook # 加载工作簿 wb = load_workbook(filename='example...
- **openstack.sh脚本**:OpenStack是一个开源的云计算管理平台,这个脚本可能是用于配置OpenStack环境,包括设置网络、安全组、实例等。 2. **Windows服务配置**(165分) - **Windows服务脚本**(Windows-1至...
### py源码实例:Python从Excel表中批量复制粘贴数据到新表 #### 背景介绍 在日常工作中,我们经常会遇到需要处理大量Excel数据的情况,比如数据汇总、清洗或是格式转换等。手动操作不仅耗时费力,而且容易出错。...
```bash pip install pandas ``` ##### 读取Excel文件 读取Excel文件的基本步骤如下: ```python import pandas as pd # 假设文件名为'example.xlsx' df = pd.read_excel('example.xlsx') print(df.head()) # ...
```bash pip install python-docx ``` #### 2. 导入库并打开文档 首先,需要导入`python-docx`库,并使用`Document`类来打开指定的Word文档: ```python from docx import Document # 打开文档 doc = Document('...