收藏 分享(赏)

bash编程实例.doc

上传人:fmgc7290 文档编号:8729061 上传时间:2019-07-09 格式:DOC 页数:14 大小:83KB
下载 相关 举报
bash编程实例.doc_第1页
第1页 / 共14页
bash编程实例.doc_第2页
第2页 / 共14页
bash编程实例.doc_第3页
第3页 / 共14页
bash编程实例.doc_第4页
第4页 / 共14页
bash编程实例.doc_第5页
第5页 / 共14页
点击查看更多>>
资源描述

1、Bourne again shell (bash) 基本编程已经在运行它如果查看一下,可能会发现:您现在正在运行 bash。因为 bash 是标准 Linux shell,并用于各种目的,所以,即使更改了缺省 shell,bash 可能仍在系统中某处运行。因为 bash 已在运行,以后运行的任何 bash 脚本都天生是有效利用内存的,因为它们与任何已运行的 bash 进程共享内存。如果正在运行的工具可以胜任工作,并且做得很好,为什么还要装入一个 500K 的解释器?已经在使用它不仅在运行 bash,实际上,您每天还在与 bash 打交道。它总在那里,因此学习如何最大限度使用它是有意义的。这样做

2、将使您的 bash 经验更有趣和有生产力。但是为什么要学习 bash 编程?很简单,因为您已在考虑如何运行命令、CPing 文件以及管道化和重定向输出。为什么不学习一种语言,以便使用和利用那些已熟悉和喜爱的强大省时的概念?命令 shell 开启了 UNIX 系统的潜能,而 bash 正是这个 Linux shell。它是您和机器之间的高级纽带。增长 bash 知识吧,这将自动提高您在 Linux 和 UNIX 中的生产力 - 就那么简单。Bash 困惑以错误方式学习 bash 令人十分困惑。许多新手输入 “man bash“ 来查看 bash 帮助页,但只得到非常简单和技术方面的 shell

3、功能性描述。还有人输入 “info bash“(来查看 GNU 信息文档) ,只能得到重新显示的帮助页,或者(如果幸运)略为友好的信息文档。尽管这可能使初学者有些失望,但标准 bash 文档无法满足所有人的要求,它只适合那些已大体熟悉 shell 编程的人。帮助页中确实有很多极好的技术信息,但对初学者的帮助却有限。这就是本系列的目的所在。在本系列中,我将讲述如何实际使用 bash 编程概念,以便编写自己的脚本。与技术描述不同,我将以简单的语言为您解释,使您不仅知道事情做什么,还知道应在何时使用。在此三部分系列末尾,您将可以自己编写复杂的 bash 脚本,并可以自如地使用 bash 以及通过阅读

4、(和理解)标准 bash 文档来补充知识。让我们开始吧。环境变量在 bash 和几乎所有其它 shell 中,用户可以定义环境变量,这些环境变量在以 ASCII 字符串存储。环境变量的最便利之处在于:它们是 UNIX 进程模型的标准部分。这意味着:环境变量不仅由 shell 脚本独用,而且还可以由编译过的标准程序使用。当在 bash 中“导出”环境变量时,以后运行的任何程序,不管是不是 shell 脚本,都可以读取设置。一个很好的例子是 vipw 命令,它通常允许 root 用户编辑系统口令文件。通过将 EDITOR 环境变量设置成喜爱的文本编辑器名称,可以配置 vipw,使其使用该编辑器,而

5、不使用 vi,如果习惯于 xemacs 而确实不喜欢 vi,那么这是很便利的。在 bash 中定义环境变量的标准方法是:$ myvar=This is my environment variable!以上命令定义了一个名为 “myvar“ 的环境变量,并包含字符串 “This is my environment variable!“。以上有几点注意事项:第一,在等号 “=“ 的两边没有空格,任何空格将导致错误(试一下看看) 。第二个件要注意的事是:虽然在定义一个字时可以省略引号,但是当定义的环境变量值多于一个字时(包含空格或制表键) ,引号是必须的。第三,虽然通常可以用双引号来替代单引号,但在

6、上例中,这样做会导致错误。为什么呢?因为使用单引号禁用了称为扩展的 bash 特性,其中,特殊字符和字符系列由值替换。例如,“!“ 字符是历史扩展字符,bash 通常将其替换为前面输入的命令。 (本系列文章中将不讲述历史扩展,因为它在 bash 编程中不常用。有关历史扩展的详细信息,请参阅 bash 帮助页中的“历史扩展”一节。 )尽管这个类似于宏的功能很便利,但我们现在只想在环境变量后面加上一个简单的感叹号,而不是宏。现在,让我们看一下如何实际使用环境变量。这有一个例子:$ echo $myvarThis is my environment variable!通过在环境变量的前面加上一个 $

7、,可以使 bash 用 myvar 的值替换它。这在 bash 术语中叫做“变量扩展” 。但是,这样做将怎样:$ echo foo$myvarbarfoo我们希望回显 “fooThis is my environment variable!bar“,但却不是这样。错在哪里?简单地说,bash 变量扩展设施陷入了困惑。它无法识别要扩展哪一个变量:$m、$my、$myvar 、$myvarbar 等等。如何更明确清楚地告述 bash 引用哪一个变量?试一下这个:$ echo foo$myvarbarfooThis is my environment variable!bar如您所见,当环境变量没有

8、与周围文本明显分开时,可以用花括号将它括起。虽然 $myvar 可以更快输入,并且在大多数情况下正确工作,但 $myvar 却能在几乎所有情况下正确通过语法分析。除此之外,二者相同,将在本系列的余下部分看到变量扩展的两种形式。请记住:当环境变量没有用空白(空格或制表键)与周围文本分开时,请使用更明确的花括号形式。回想一下,我们还提到过可以“导出”变量。当导出环境变量时,它可以自动地由以后运行的任何脚本或可执行程序环境使用。shell 脚本可以使用 shell 的内置环境变量支持“到达”环境变量,而 C 程序可以使用 getenv() 函数调用。这里有一些 C 代码示例,输入并编译它们 - 它将

9、帮助我们从 C 的角度理解环境变量:myvar.c - 样本环境变量 C 程序#include #include int main(void) char *myenvvar=getenv(“EDITOR“);printf(“The editor environment variable is set to %sn“,myenvvar);将上面的代码保存到文件 myenv.c 中,然后发出以下命令进行编译:$ gcc myenv.c -o myenv现在,目录中将有一个可执行程序,它在运行时将打印 EDITOR 环境变量的值(如果有值的话) 。这是在我机器上运行时的情况:$ ./myenvThe

10、 editor environment variable is set to (null)啊. 因为没有将 EDITOR 环境变量设置成任何值,所以 C 程序得到一个空字符串。让我们试着将它设置成特定值:$ EDITOR=xemacs$ ./myenvThe editor environment variable is set to (null)虽然希望 myenv 打印值 “xemacs“,但是因为还没有导出环境变量,所以它却没有很好地工作。这次让它正确工作:$ export EDITOR$ ./myenvThe editor environment variable is set to x

11、emacs现在,如您亲眼所见:不导出环境变量,另一个进程(在本例中是示例 C 程序)就看不到环境变量。顺便提一句,如果愿意,可以在一行定义并导出环境变量,如下所示:$ export EDITOR=xemacs这与两行版本的效果相同。现在该演示如何使用 unset 来除去环境变量:$ unset EDITOR$ ./myenvThe editor environment variable is set to (null)截断字符串概述截断字符串是将初始字符串截断成较小的独立块,它是一般 shell 脚本每天执行的任务之一。很多时候,shell 脚本需要采用全限定路径,并找到结束的文件或目录。虽然

12、可以用 bash 编码实现(而且有趣) ,但标准 basename UNIX 可执行程序可以极好地完成此工作:$ basename /usr/local/share/doc/foo/foo.txtfoo.txt$ basename /usr/home/drobbinsdrobbinsBasename 是一个截断字符串的极简便工具。它的相关命令 dirname 返回 basename 丢弃的“另”一部分路径。$ dirname /usr/local/share/doc/foo/foo.txt/usr/local/share/doc/foo$ dirname /usr/home/drobbins/

13、usr/home命令替换需要知道一个简便操作:如何创建一个包含可执行命令结果的环境变量。这很容易:$ MYDIR=dirname /usr/local/share/doc/foo/foo.txt$ echo $MYDIR/usr/local/share/doc/foo上面所做的称为“命令替换” 。此例中有几点需要指出。在第一行,简单地将要执行的命令以 反引号括起。那不是标准的单引号,而是键盘中通常位于 Tab 键之上的单引号。可以用 bash 备用命令替换语法来做同样的事:$ MYDIR=$(dirname /usr/local/share/doc/foo/foo.txt)$ echo $MY

14、DIR/usr/local/share/doc/foo如您所见,bash 提供多种方法来执行完全一样的操作。使用命令替换可以将任何命令或命令管道放在 或 $( ) 之间,并将其分配给环境变量。真方便!下面是一个例子,演示如何在命令替换中使用管道:MYFILES=$(ls /etc | grep pa)bash-2.03$ echo $MYFILESpam.d passwd象专业人员那样截断字符串尽管 basename 和 dirname 是很好的工具,但有时可能需要执行更高级的字符串“截断” ,而不只是标准的路径名操作。当需要更强的说服力时,可以利用 bash 内置的变量扩展功能。已经使用了类

15、似于 $MYVAR 的标准类型的变量扩展。但是 bash 自身也可以执行一些便利的字符串截断。看一下这些例子:$ MYVAR=foodforthought.jpg$ echo $MYVAR#*forthought.jpg$ echo $MYVAR#*foodforthought.jpg在第一个例子中,输入了 $MYVAR#*fo。它的确切含义是什么?基本上,在 $ 中输入环境变量名称,两个 #,然后是通配符 (“*fo“)。然后,bash 取得 MYVAR,找到从字符串 “foodforthought.jpg“ 开始处开始、且匹配通配符 “*fo“ 的最长子字符串,然后将其从字符串的开始处截去

16、。刚开始理解时会有些困难,为了感受一下这个特殊的 “#“ 选项如何工作,让我们一步步地看看 bash 如何完成这个扩展。首先,它从 “foodforthought.jpg“ 的开始处搜索与 “*fo“ 通配符匹配的子字符串。以下是检查到的子字符串:f fo MATCHES *fofoofoodfoodf foodfo MATCHES *fofoodforfoodfort foodforthfoodfortho foodforthoufoodforthougfoodforthoughtfoodforthought.jfoodforthought.jpfoodforthought.jpg在搜索了匹

17、配的字符串之后,可以看到 bash 找到两个匹配。它选择最长的匹配,从初始字符串的开始处除去,然后返回结果。上面所示的第二个变量扩展形式看起来与第一个相同,但是它只使用一个 “#“ - 并且 bash 执行几乎同样的过程。它查看与第一个例子相同的子字符串系列,但是 bash 从初始字符串除去最短的匹配,然后返回结果。所以,一查到 “fo“ 子字符串,它就从字符串中除去 “fo“,然后返回 “odforthought.jpg“。这样说可能会令人十分困惑,下面以一简单方式记住这个功能。当搜索最长匹配时,使用 #(因为 # 比 # 长) 。当搜索最短匹配时,使用 #。看,不难记吧!等一下,怎样记住应

18、该使用 # 字符来从字符串开始部分除去?很简单!注意到了吗:在美国键盘上,shift-4 是 “$“,它是 bash 变量扩展字符。在键盘上,紧靠 “$“ 左边的是 “#“。这样,可以看到:“#“ 位于 “$“ 的“开始处” ,因此(根据我们的记忆法) ,“#“ 从字符串的开始处除去字符。您可能要问:如何从字符串末尾除去字符。如果猜到我们使用美国键盘上紧靠 “$“ 右边的字符 (“%),那就猜对了。这里有一些简单的例子,解释如何截去字符串的末尾部分:$ MYFOO=“chickensoup.tar.gz“$ echo $MYFOO%.*chickensoup$ echo $MYFOO%.*ch

19、ickensoup.tar正如您所见,除了将匹配通配符从字符串末尾除去之外,% 和 % 变量扩展选项与 # 和 # 的工作方式相同。请注意:如果要从末尾除去特定子字符串,不必使用 “*“ 字符:MYFOOD=“chickensoup“$ echo $MYFOOD%soupchicken在此例中,使用 “%“ 或 “%“ 并不重要,因为只能有一个匹配。还要记住:如果忘记了应该使用 “#“ 还是 “%“,则看一下键盘上的 3、4 和 5 键,然后猜出来。可以根据特定字符偏移和长度,使用另一种形式的变量扩展,来选择特定子字符串。试着在 bash 中输入以下行:$ EXCLAIM=cowabunga$

20、 echo $EXCLAIM:0:3cow$ echo $EXCLAIM:3:7abunga这种形式的字符串截断非常简便,只需用冒号分开来指定起始字符和子字符串长度。应用字符串截断现在我们已经学习了所有截断字符串的知识,下面写一个简单短小的 shell 脚本。我们的脚本将接受一个文件作为自变量,然后打印:该文件是否是一个 tar 文件。要确定它是否是 tar 文件,将在文件末尾查找模式 “.tar“。如下所示:mytar.sh - 一个简单的脚本#!/bin/bashif “$1#*.“ = “tar“ thenecho This appears to be a tarball.elseech

21、o At first glance, this does not appear to be a tarball.fi要运行此脚本,将它输入到文件 mytar.sh 中,然后输入 “chmod 755 mytar.sh“,生成可执行文件。然后,如下做一下 tar 文件试验:$ ./mytar.sh thisfile.tarThis appears to be a tarball.$ ./mytar.sh thatfile.gzAt first glance, this does not appear to be a tarball.好,成功运行,但是不太实用。在使它更实用之前,先看一下上面使用的

22、 “if“ 语句。语句中使用了一个布尔表达式。在 bash 中,“=“ 比较运算符检查字符串是否相等。在 bash 中,所有布尔表达式都用方括号括起。但是布尔表达式实际上测试什么?让我们看一下左边。根据前面所学的字符串截断知识,“$1#*.“ 将从环境变量 “1“ 包含的字符串开始部分除去最长的 “*.“ 匹配,并返回结果。这将返回文件中最后一个 “.“ 之后的所有部分。显然,如果文件以 “.tar“ 结束,结果将是 “tar“,条件也为真。您可能会想:开始处的 “1“ 环境变量是什么。很简单 - $1 是传给脚本的第一个命令行自变量,$2 是第二个,以此类推。好,已经回顾了功能,下面来初探

23、“if“ 语句。If 语句与大多数语言一样,bash 有自己的条件形式。在使用时,要遵循以上格式;即,将 “if“ 和 “then“ 放在不同行,并使 “else“ 和结束处必需的 “fi“ 与它们水平对齐。这将使代码易于阅读和调试。除了 “if,else“ 形式之外,还有其它形式的 “if“ 语句:if condition thenactionfi只有当 condition 为真时,该语句才执行操作,否则不执行操作,并继续执行 “fi“ 之后的任何行。if condition thenactionelif condition2 thenaction2.elif condition3 then

24、elseactionxfi以上 “elif“ 形式将连续测试每个条件,并执行符合第一个真条件的操作。如果没有条件为真,则将执行 “else“ 操作,如果有一个条件为真,则继续执行整个 “if,elif,else“ 语句之后的行。接收自变量在 介绍性文章中的样本程序中,我们使用环境变量 “$1“ 来引用第一个命令行自变量。类似地,可以使用 “$2“、“$3“ 等来引用传递给脚本的第二和第三个自变量。这里有一个例子:#!/usr/bin/env bashecho name of script is $0echo first argument is $1echo second argument is

25、 $2echo seventeenth argument is $17echo number of arguments is $#除以下两个细节之外,此例无需说明。第一,“$0“ 将扩展成从命令行调用的脚本名称,“$#“ 将扩展成传递给脚本的自变量数目。试验以上脚本,通过传递不同类型的命令行自变量来了解其工作原理。有时需要一次引用所有命令行自变量。针对这种用途,bash 实现了变量 “$“,它扩展成所有用空格分开的命令行参数。在本文稍后的 “for“ 循环部分中,您将看到使用该变量的例子。Bash 编程结构如果您曾用过如 C、Pascal、Python 或 Perl 那样的过程语言编程,则一定

26、熟悉 “if“ 语句和 “for“ 循环那样的标准编程结构。对于这些标准结构的大多数,Bash 有自己的版本。在下几节中,将介绍几种 bash 结构,并演示这些结构和您已经熟悉的其它编程语言中结构的差异。如果以前编程不多,也不必担心。我提供了足够的信息和示例,使您可以跟上本文的进度。方便的条件语句如果您曾用 C 编写过与文件相关的代码,则应该知道:要比较特定文件是否比另一个文件新需要大量工作。那是因为 C 没有任何内置语法来进行这种比较,必须使用两个 stat() 调用和两个 stat 结构来进行手工比较。相反,bash 内置了标准文件比较运算符,因此,确定“/tmp/myfile 是否可读”

27、与查看“$myvar 是否大于 4”一样容易。下表列出最常用的 bash 比较运算符。同时还有如何正确使用每一选项的示例。示例要跟在 “if“ 之后。例如:if -z “$myvar“ thenecho “myvar is not defined“fi运算符 描述 示例文件比较运算符-e filename 如果 filename 存在,则为真 -e /var/log/syslog -d filename 如果 filename 为目录,则为真 -d /tmp/mydir -f filename 如果 filename 为常规文件,则为真 -f /usr/bin/grep -L filename

28、 如果 filename 为符号链接,则为真 -L /usr/bin/grep -r filename 如果 filename 可读,则为真 -r /var/log/syslog -w filename 如果 filename 可写,则为真 -w /var/mytmp.txt -x filename 如果 filename 可执行,则为真 -L /usr/bin/grep filename1 -nt filename2 如果 filename1 比 filename2 新,则为真 /tmp/install/etc/services -nt /etc/services filename1 -ot

29、 filename2 如果 filename1 比 filename2 旧,则为真 /boot/bzImage -ot arch/i386/boot/bzImage 字符串比较运算符 (请注意引号的使用,这是防止空格扰乱代码的好方法)-z string 如果 string 长度为零,则为真 -z “$myvar“ -n string 如果 string 长度非零,则为真 -n “$myvar“ string1 = string2 如果 string1 与 string2 相同,则为真 “$myvar“ = “one two three“ string1 != string2 如果 string

30、1 与 string2 不同,则为真 “$myvar“ != “one two three“ 算术比较运算符num1 -eq num2 等于 3 -eq $mynum num1 -ne num2 不等于 3 -ne $mynum num1 -lt num2 小于 3 -lt $mynum num1 -le num2 小于或等于 3 -le $mynum num1 -gt num2 大于 3 -gt $mynum num1 -ge num2 大于或等于 3 -ge $mynum 有时,有几种不同方法来进行特定比较。例如,以下两个代码段的功能相同:if “$myvar“ -eq 3 thenech

31、o “myvar equals 3“fiif “$myvar“ = “3“ thenecho “myvar equals 3“fi上面两个比较执行相同的功能,但是第一个使用算术比较运算符,而第二个使用字符串比较运算符。字符串比较说明大多数时候,虽然可以不使用括起字符串和字符串变量的双引号,但这并不是好主意。为什么呢?因为如果环境变量中恰巧有一个空格或制表键,bash 将无法分辨,从而无法正常工作。这里有一个错误的比较示例:if $myvar = “foo bar oni“ thenecho “yes“fi在上例中,如果 myvar 等于 “foo“,则代码将按预想工作,不进行打印。但是,如果

32、myvar 等于 “foo bar oni“,则代码将因以下错误失败:: too many arguments在这种情况下,“$myvar“(等于 “foo bar oni“)中的空格迷惑了 bash。bash 扩展 “$myvar“ 之后,代码如下: foo bar oni = “foo bar oni“ 因为环境变量没放在双引号中,所以 bash 认为方括号中的自变量过多。可以用双引号将字符串自变量括起来消除该问题。请记住,如果养成将所有字符串自变量用双引号括起的习惯,将除去很多类似的编程错误。“foo bar oni“ 比较应该写成:if “$myvar“ = “foo bar oni“

33、 thenecho “yes“fi以上代码将按预想工作,而不会有任何令人不快的意外出现。循环结构:“for“好了,已经讲了条件语句,下面该探索 bash 循环结构了。我们将从标准的 “for“ 循环开始。这里有一个简单的例子:#!/usr/bin/env bashfor x in one two three fourdoecho number $xdone输出:number onenumber twonumber threenumber four发生了什么?“for“ 循环中的 “for x“ 部分定义了一个名为 “$x“ 的新环境变量(也称为循环控制变量) ,它的值被依次设置为 “one“、

34、“two“、 “three“ 和 “four“。每一次赋值之后,执行一次循环体(“do“ 和 “done“ 之间的代码) 。在循环体内,象其它环境变量一样,使用标准的变量扩展语法来引用循环控制变量 “$x“。还要注意,“for“ 循环总是接收 “in“ 语句之后的某种类型的字列表。在本例中,指定了四个英语单词,但是字列表也可以引用磁盘上的文件,甚至文件通配符。看看下面的例子,该例演示如何使用标准 shell 通配符:#!/usr/bin/env bashfor myfile in /etc/r*doif -d “$myfile“ thenecho “$myfile (dir)“elseecho

35、 “$myfile“fidone输出:/etc/rc.d (dir)/etc/resolv.conf/etc/resolv.conf/etc/rpc 以上代码列出在 /etc 中每个以 “r“ 开头的文件。要做到这点,bash 在执行循环之前首先取得通配符 /etc/r*,然后扩展它,用字符串 /etc/rc.d /etc/resolv.conf /etc/resolv.conf /etc/rpc 替换。一旦进入循环,根据 myfile 是否为目录,“-d“ 条件运算符用来执行两个不同操作。如果是目录,则将 “(dir)“ 附加到输出行。还可以在字列表中使用多个通配符、甚至是环境变量:for

36、x in /etc/r? /var/lo* /home/drobbins/mystuff/* /tmp/$MYPATH/*docp $x /mnt/mydirdoneBash 将在所有正确位置上执行通配符和环境变量扩展,并可能创建一个非常长的字列表。虽然所有通配符扩展示例使用了绝对路径,但也可以使用相对路径,如下所示:for x in /* mystuff/*doecho $x is a silly filedone在上例中,bash 相对于当前工作目录执行通配符扩展,就象在命令行中使用相对路径一样。研究一下通配符扩展。您将注意到,如果在通配符中使用绝对路径,bash 将通配符扩展成一个绝对路

37、径列表。否则,bash 将在后面的字列表中使用相对路径。如果只引用当前工作目录中的文件(例如,如果输入 “for x in *“) ,则产生的文件列表将没有路径信息的前缀。请记住,可以使用 “basename“ 可执行程序来除去前面的路径信息,如下所示:for x in /var/log/*doecho basename $x is a file living in /var/logdone当然,在脚本的命令行自变量上执行循环通常很方便。这里有一个如何使用本文开始提到的 “$“ 变量的例子:#!/usr/bin/env bashfor thing in “$“doecho you typed

38、$thing.done输出:$ allargs hello there you sillyyou typed hello.you typed there.you typed you.you typed silly.Shell 算术在学习另一类型的循环结构之前,最好先熟悉如何执行 shell 算术。是的,确实如此:可以使用 shell 结构来执行简单的整数运算。只需将特定的算术表达式用 “$(“ 和 “)“ 括起,bash 就可以计算表达式。这里有一些例子:$ echo $( 100 / 3 )33$ myvar=“56“$ echo $( $myvar + 12 )68$ echo $( $m

39、yvar - $myvar )0 $ myvar=$( $myvar + 1 )$ echo $myvar57您已经熟悉如何执行数学操作,现在该介绍其它两种 bash 循环结构 “while“ 和 “until“ 了。更多的循环结构:“while“ 和 “until“只要特定条件为真,“while“ 语句就会执行,其格式如下while condition dostatementsdone通常使用 “While“ 语句来循环一定次数,比如,下例将循环 10 次:myvar=0while $myvar -ne 10 doecho $myvarmyvar=$( $myvar + 1 )done可以看

40、到,上例使用了算术表达式来使条件最终为假,并导致循环终止。“Until“ 语句提供了与 “while“ 语句相反的功能:只要特定条件为假,它们就重复。下面是一个与前面的 “while“ 循环具有同等功能的 “until“ 循环:myvar=0until $myvar -eq 10 doecho $myvarmyvar=$( $myvar + 1 )doneCase 语句Case 语句是另一种便利的条件结构。这里有一个示例片段:case “$x#*.“ ingz)gzunpack $SROOT/$x;bz2)bz2unpack $SROOT/$x;*)echo “Archive format n

41、ot recognized.“exit;esac 在上例中,bash 首先扩展 “$x#*.“。在代码中,“$x“ 是文件的名称,“$x#.*“ 除去文件中最后句点后文本之外的所有文本。然后,bash 将产生的字符串与 “)“ 左边列出的值做比较。在本例中,“$x#.*“ 先与 “gz“ 比较,然后是 “bz2“,最后是 “*“。如果 “$x#.*“ 与这些字符串或模式中的任何一个匹配,则执行紧接 “)“ 之后的行,直到 “;“ 为止,然后 bash 继续执行结束符 “esac“ 之后的行。如果不匹配任何模式或字符串,则不执行任何代码行,在这个特殊的代码片段中,至少要执行一个代码块,因为任何不

42、与 “gz“ 或 “bz2“ 匹配的字符串都将与 “*“ 模式匹配。函数与名称空间在 bash 中,甚至可以定义与其它过程语言(如 Pascal 和 C)类似的函数。在 bash 中,函数甚至可以使用与脚本接收命令行自变量类似的方式来接收自变量。让我们看一下样本函数定义,然后再从那里继续:tarview() echo -n “Displaying contents of $1 “if $1#*. = tar thenecho “(uncompressed tar)“tar tvf $1elif $1#*. = gz thenecho “(gzip-compressed tar)“tar tzv

43、f $1elif $1#*. = bz2 thenecho “(bzip2-compressed tar)“cat $1 | bzip2 -d | tar tvf -fi我们在上面定义了一个名为 “tarview“ 的函数,它接收一个自变量,即某种类型的 tar 文件。在执行该函数时,它确定自变量是哪种 tar 文件类型(未压缩的、 gzip 压缩的或 bzip2 压缩的) ,打印一行信息性消息,然后显示 tar 文件的内容。应该如下调用上面的函数(在输入、粘贴或找到该函数后,从脚本或命令行调用它):$ tarview shorten.tar.gzDisplaying contents of

44、shorten.tar.gz (gzip-compressed tar)drwxr-xr-x ajr/abbot 0 1999-02-27 16:17 shorten-2.3a/-rw-r-r- ajr/abbot 1143 1997-09-04 04:06 shorten-2.3a/Makefile-rw-r-r- ajr/abbot 1199 1996-02-04 12:24 shorten-2.3a/INSTALL-rw-r-r- ajr/abbot 839 1996-05-29 00:19 shorten-2.3a/LICENSE如您所见,可以使用与引用命令行自变量同样的机制来在函数定

45、义内部引用自变量。另外,将把 “$#“ 宏扩展成包含自变量的数目。唯一可能不完全相同的是变量 “$0“,它将扩展成字符串 “bash“(如果从 shell 交互运行函数)或调用函数的脚本名称。名称空间经常需要在函数中创建环境变量。虽然有可能,但是还有一个技术细节应该了解。在大多数编译语言(如 C)中,当在函数内部创建变量时,变量被放置在单独的局部名称空间中。因此,如果在 C 中定义一个名为 myfunction 的函数,并在该函数中定义一个名为 “x“ 的自变量,则任何名为 “x“ 的全局变量(函数之外的变量)将不受它的印象,从而消除了负作用。在 C 中是这样,但在 bash 中却不是。在 b

46、ash 中,每当在函数内部创建环境变量,就将其添加到全局名称空间。这意味着,该变量将重写函数之外的全局变量,并在函数退出之后继续存在:#!/usr/bin/env bashmyvar=“hello“myfunc() myvar=“one two three“for x in $myvardoecho $xdonemyfuncecho $myvar $x运行此脚本时,它将输出 “one two three three“,这显示了在函数中定义的 “$myvar“ 如何影响全局变量 “$myvar“,以及循环控制变量 “$x“ 如何在函数退出之后继续存在(如果 “$x“ 全局变量存在,也将受到影响)

47、 。在这个简单的例子中,很容易找到该错误,并通过使用其它变量名来改正错误。但这不是正确的方法,解决此问题的最好方法是通过使用 “local“ 命令,在一开始就预防影响全局变量的可能性。当使用 “local“ 在函数内部创建变量时,将把它们放在局部名称空间中,并且不会影响任何全局变量。这里演示了如何实现上述代码,以便不重写全局变量:#!/usr/bin/env bashmyvar=“hello“myfunc() local xlocal myvar=“one two three“for x in $myvardoecho $xdonemyfuncecho $myvar $x此函数将输出 “hello“ - 不重写全局变量 “$myvar“,“$x“ 在 myfunc 之外不继续存在。在函数的第一行,我们创建了以后要使用的局部变量 x,而在第二个例子 (local myvar=“one two three“) 中,我们创建了局部变量 myvar,同时为其赋值。在将循环控制变量定义为局部变量时,使用第一种形式很方便,因为不允许说:“for local x in $myvar“。此函数不影响任何全局变量,鼓励您用这种方式设计所有的函数。只有在明确希望要修改全局变量时,才 不应该使用 “local“。

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报