当前位置:Linux教程 - Linux资讯 - Bash 实例 (2)

Bash 实例 (2)

  在前一篇 bash 的介绍性文章中,Daniel Robbins 为您讲解了脚本语言的一些基本元素和使用 bash 的原因。在本文(即第二部分)中,Daniel 继续前一篇的内容,并讲解条件 (if-then) 语句、循环和更多的 bash 基本结构。  我们先看一下处理命令行自变量的简单技巧,然后再看看 bash 基本编程结构。  接收自变量  在 介绍性文章中的样本程序中,我们使用环境变量 "$1" 来引用第一个命令行自变量。类似地,可以使用 "$2"、"$3" 等来引用传递给脚本的第二和第三个自变量。这里有一个例子:  #!/usr/bin/env bash  echo name of script is $0  echo first argument is $1  echo second argument is $2  echo seventeenth argument is $17  echo number of arguments is $#  除以下两个细节之外,此例无需说明。第一,"$0" 将扩展成从命令行调用的脚本名称,"$#" 将扩展成传递给脚本的自变量数目。试验以上脚本,通过传递不同类型的命令行自变量来了解其工作原理。  有时需要一次引用所有命令行自变量。针对这种用途,bash 实现了变量 "$@",它扩展成所有用空格分开的命令行参数。在本文稍后的 "for" 循环部分中,您将看到使用该变量的例子。  Bash 编程结构  如果您曾用过如 C、Pascal、Python 或 Perl 那样的过程语言编程,则一定熟悉 "if" 语句和 "for" 循环那样的标准编程结构。对于这些标准结构的大多数,Bash 有自己的版本。在下几节中,将介绍几种 bash 结构,并演示这些结构和您已经熟悉的其它编程语言中结构的差异。如果以前编程不多,也不必担心。我提供了足够的信息和示例,使您可以跟上本文的进度。  方便的条件语句  如果您曾用 C 编写过与文件相关的代码,则应该知道:要比较特定文件是否比另一个文件新需要大量工作。那是因为 C 没有任何内置语法来进行这种比较,必须使用两个 stat() 调用和两个 stat 结构来进行手工比较。相反,bash 内置了标准文件比较运算符,因此,确定“/tmp/myfile 是否可读”与查看“$myvar 是否大于 4”一样容易。  下表列出最常用的 bash 比较运算符。同时还有如何正确使用每一选项的示例。示例要跟在 "if" 之后。例如:  if [ -z "$myvar" ]  then   echo "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 如果 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 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 如果 string1 与 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 ]  then   echo "myvar equals 3"  fi  if [ "$myvar" = "3" ]  then   echo "myvar equals 3"  fi  上面两个比较执行相同的功能,但是第一个使用算术比较运算符,而第二个使用字符串比较运算符。  字符串比较说明  大多数时候,虽然可以不使用括起字符串和字符串变量的双引号,但这并不是好主意。为什么呢?因为如果环境变量中恰巧有一个空格或制表键,bash 将无法分辨,从而无法正常工作。这里有一个错误的比较示例:  if [ $myvar = "foo bar oni" ]  then   echo "yes"  fi  在上例中,如果 myvar 等于 "foo",则代码将按预想工作,不进行打印。但是,如果 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" ]  then   echo "yes"  fi  更多引用细节  如果要扩展环境变量,则必须将它们用双引号、而不是单引号括起。单引号 禁用变量(和历史)扩展。  以上代码将按预想工作,而不会有任何令人不快的意外出现。  循环结构:"for"  好了,已经讲了条件语句,下面该探索 bash 循环结构了。我们将从标准的 "for" 循环开始。这里有一个简单的例子:  #!/usr/bin/env bash  for x in one two three four  do  echo number $x  done  输出:  number one  number two   number three   number four  发生了什么?"for" 循环中的 "for x" 部分定义了一个名为 "$x" 的新环境变量(也称为循环控制变量),它的值被依次设置为 "one"、"two"、"three" 和 "four"。每一次赋值之后,执行一次循环体("do" 和 "done" 之间的代码)。在循环体内,象其它环境变量一样,使用标准的变量扩展语法来引用循环控制变量 "$x"。还要注意,"for" 循环总是接收 "in" 语句之后的某种类型的字列表。在本例中,指定了四个英语单词,但是字列表也可以引用磁盘上的文件,甚至文件通配符。看看下面的例子,该例演示如何使用标准 shell 通配符:  #!/usr/bin/env bash  for myfile in /etc/r*  do  if [ -d "$myfile" ]   then   echo "$myfile (dir)"  else  echo "$myfile"  fi  done  输出:  /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 x in /etc/r??? /var/lo* /home/drobbins/mystuff/* /tmp/${MYPATH}/*  do  cp $x /mnt/mydir  done  Bash 将在所有正确位置上执行通配符和环境变量扩展,并可能创建一个非常长的字列表。  虽然所有通配符扩展示例使用了绝对路径,但也可以使用相对路径,如下所示:  for x in ../* mystuff/*  do  echo $x is a silly file  done  在上例中,bash 相对于当前工作目录执行通配符扩展,就象在命令行中使用相对路径一样。研究一下通配符扩展。您将注意到,如果在通配符中使用绝对路径,bash 将通配符扩展成一个绝对路径列表。否则,bash 将在后面的字列表中使用相对路径。如果只引用当前工作目录中的文件(例如,如果输入 "for x in *"),则产生的文件列表将没有路径信息的前缀。请记住,可以使用 "basename" 可执行程序来除去前面的路径信息,如下所示:  for x in /var/log/*  do  echo `basename $x` is a file living in /var/log  done  当然,在脚本的命令行自变量上执行循环通常很方便。这里有一个如何使用本文开始提到的 "$@" 变量的例子:  #!/usr/bin/env bash  for thing in "$@"  do  echo you typed ${thing}.  done  输出:  $ allargs hello there you silly  you 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 $(( $myvar - $myvar ))  0 $ myvar=$(( $myvar + 1 ))  $ echo $myvar  57  您已经熟悉如何执行数学操作,现在该介绍其它
[1] [2] 下一页 

(出处:http://www.sheup.com)


上一页 [1] [2]