流程控制if
http://www.openchess.org/noitatsko/programming/ (2001-05-25 16:10:00)
if list then list [ elif list then list ] ... [ else list ] fi 几种可能的写法 -------------------------------------------------------------------------------- 第一种 if list then do something here fi 当list表述返回值为True(0)时,将会执行"do something here"。 例一 : 当我们要执行一个命令或程式之前,有时候需要检查该命令是否存在,然後才执行。 if [ -x /sbin/quotaon ] ; then echo "Turning on Quota for root filesystem" /sbin/quotaon / fi 例二 : 当我们将某个档案做为设定档时,可先检查是否存在,然後将该档案设定值载入。 # Filename : /etc/ppp/settings PHONE=1-800-COLLECT #!/bin/sh # Filename : phonebill if [ -f /etc/ppp/settings ] ; then source /etc/ppp/settings echo $PHONE fi 执行 [foxman@foxman ppp]# ./phonebill 1-800-COLLECT
» 相关连接:
[回复]
--------------------------------------------------------------------------------
第二种 if list then do something here else do something else here fi 例三 : Hostname #!/bin/sh if [ -f /etc/HOSTNAME ] ; then HOSTNAME=`cat /etc/HOSTNAME` else HOSTNAME=localhost fi -------------------------------------------------------------------------------- 第三种 if list then do something here elif list then do another thing here fi 例四 : 如果某个设定档允许有好几个位置的话,例如crontab,可利用if then elif fi来找寻。 #!/bin/sh if [ -f /etc/crontab ] ; then CRONTAB="/etc/crontab" elif [ -f /var/spool/cron/crontabs/root ] ; then CRONTAB="/var/spool/cron/crontabs/root" elif [ -f /var/cron/tabs/root ] ; then CRONTAB="/var/cron/tabs/root" fi export CRONTAB -------------------------------------------------------------------------------- 第四种 if list then do something here elif list then do another thing here else do something else here fi 例五 : 我们可利用uname来判断目前系统,并分别做各系统状况不同的事。 #!/bin/sh SYSTEM=`uname -s` if [ $SYSTEM = "Linux" ] ; then echo "Linux" elif [ $SYSTEM = "FreeBSD" ] ; then echo "FreeBSD" elif [ $SYSTEM = "Solaris" ] ; then echo "Solaris" else echo "What?" fi
» 相关连接:
[回复]
本章我们会讨论在Bash脚本中使用条件,包含以下几个话题:
有时候你需要指定shell脚本中的依靠命令的成功与否来实施不同过程的行为。 if 结构允许你来指定这样的条件。 最精简的 if 命令的语法是:
TEST-COMMAND 执行后且它的返回状态是0,那么 CONSEQUENT-COMMANDS 就执行。返回状态是最后一个命令的退出状态,或者当没有条件是真的话为0。 TEST-COMMAND 经常包括数字和字符串的比较测试,但是也可以是任何在成功时返回状态0或者失败时返回一些其他状态的一些命令。一元表达式经常用于检查文件的状态。如果对某个要素primaries, 下表包含了一个组成 TEST-COMMAND 命令或者命令列表,称作 “要素primaries” 的概览。这些primaries放置在方括号中来表示一个条件表达式的测试。 表 7.1. 主表达式
表达式可以借以下操作符组合起来,以降序列出:listed in decreasing order of precedence: 表 7.2. 组合表达式
[ (或作 test) 内建命令对条件表达式使用一系列基于参数数量的规则来求值。更多关于这个主题的信息可以在Bash文档中查找。就像if 使用fi 来结束一样,在条件列完之后必须用">"来结束。 CONSEQUENT-COMMANDS 列出了跟在 then 语句后面可以是任何有效的UNIX命令,任何可执行的程序,任何可执行的shell脚本或者任何shell语句,除了 fi. 。重要地记住 then 和 fi 在shell里面被认为是分开的语句。因此,在命令行上使用的时候,他们用分号隔开。 在脚本中,if语句的不同部分通常是良好分隔的。以下是一些简单的例子: 第一个例子检查一个文件是否存在:
加入到你的Bash配置文件中去: # These lines will print a message if the noclobber option is set:
以下的例子显示了一个简单的测试:
以下的例子证明了 TEST-COMMANDS 可以是任何有返回和退出状态的UNIX命令,之后 if 再次返回零的退出状态:
以下能得到同样的结果:
以下的例子是用了数值的比较:
这个脚本在每个星期天由cron来执行。如果星期的数是偶数,他就提醒你把垃圾箱清理: #!/bin/bash 一个通过比较字符串来测试用户ID的例子: if [ "$(whoami)" != 'root' ]; then 使用Bash,你可以缩短这样的结构。下面是以上测试的精简结构: [ "$(whoami)" != 'root' ] && ( echo you are using a non-privileged account; exit 1 ) 类似于如果测试为真就执行的 “&&” 表达式, “||” 指定了测试为假就执行。类似于 “&&” 表达式指明了在两个测试条件为真时所采取的动作,“||” 指明测试为假时所采取的行动。 正则表达式也可以在比较中使用:
参见信息页面得到更多关于Bash “(( EXPRESSION ))” 和 “[[ EXPRESSION ]]” 结构的模块匹配信息。
» 相关连接:
[回复]
7.2.1. if/then/else结构
7.2.1.1. 虚构的例子 这是一个如果 if 命令测试为真,另外一个 if 测试是假而采取的一系列动作的结构。例子: freddy scripts> gender="male" freddy scripts> if [[ "$gender" == "f*" ]] More input> then echo "Pleasure to meet you, Madame." More input> else echo "How come the lady hasn't got a drink yet?" More input> fi How come the lady hasn't got a drink yet? freddy scripts> 就像 CONSEQUENT-COMMANDS 跟在 then 语句后面一样,ALTERNATE-CONSEQUENT-COMMANDS跟在 else 后面并可以使用任何有返回状态的UNIX风格命令。 另外一个例子,从 第 7.1.2.1 节 “测试退出状态” 扩展开来: anny ~> su - Password: [root@elegance root]# if ! grep ^$USER /etc/passwd 1> /dev/null > then echo "your user account is not managed locally" > else echo "your account is managed from the local /etc/passwd file" > fi your account is managed from the local /etc/passwd file [root@elegance root]# 我们切换到 root 账号来证明 else 语句的效果- 你的 root 通常是一个本地账号,有时你自己的账号可能被一个特定的中央系统管理着,比如LDAP服务器。 7.2.1.2. 检查命令行参数 除了设置完参数然后运行脚本之外,通常更好的方法是通过命令行给变量设置值。 我们使用位置参数 $1, $2,..., $N来达到此目的。 $#代表了命令行的参数数量, $0代表了脚本的名字。 以下是一个简单的例子: 图 7.1. 使用if来测试命令行参数 Simple if/then/else/fi construct: if [ "$1" == fish ]; then echo "Tux likes this"; else echo "Tux wants fish!"; fi 这里是另外一个例子,使用2个参数: anny ~> cat weight.sh #!/bin/bash # This script prints a message about your weight if you give it your # weight in kilos and hight in centimeters. weight="$1" height="$2" idealweight=$[$height - 110] if [ $weight -le $idealweight ] ; then echo "You should eat a bit more fat." else echo "You should eat a bit more fruit." fi anny ~> bash -x weight.sh 55 169 + weight=55 + height=169 + idealweight=59 + '[' 55 -le 59 ']' + echo 'You should eat a bit more fat.' You should eat a bit more fat. 7.2.1.3. 测试参数的数量 以下的例子显示了怎么改变之前的脚本如果参数少于或者多余2个来打印出一条消息: anny ~> cat weight.sh #!/bin/bash # This script prints a message about your weight if you give it your # weight in kilos and hight in centimeters. if [ ! $# == 2 ]; then echo "Usage: $0 weight_in_kilos length_in_centimeters" exit fi weight="$1" height="$2" idealweight=$[$height - 110] if [ $weight -le $idealweight ] ; then echo "You should eat a bit more fat." else echo "You should eat a bit more fruit." fi anny ~> weight.sh 70 150 You should eat a bit more fruit. anny ~> weight.sh 70 150 33 Usage: ./weight.sh weight_in_kilos length_in_centimeters 第一个参数代表$1,第二个参数代表$2,以此类推,参数数量的总数存在$#中。 查阅 第 7.2.5 节 “使用exit语句和if” 来得到更好的打印消息的方法。 7.2.1.4. 测试一个存在的文件 在许多脚本当中这个测试都成功,因为如果你知道某些功能不工作那运行很多程序也是没有用的: #!/bin/bash # This script gives information about a file. FILENAME="$1" echo "Properties for $FILENAME:" if [ -f $FILENAME ]; then echo "Size is $(ls -lh $FILENAME | awk '{ print $5 }')" echo "Type is $(file $FILENAME | cut -d":" -f2 -)" echo "Inode number is $(ls -i $FILENAME | cut -d" " -f1 -)" echo "$(df -h $FILENAME | grep -v Mounted | awk '{ print "On",$1", \ which is mounted as the",$6,"partition."}')" else echo "File does not exist." fi 注意文件是使用变量来指向的;在这个例子中它是脚本的第一个参数。另外,当没有提供任何参数的时候,文件的存放位置通常存储在脚本开始处的变量里,他们的内容是依赖于使用的那些变量。因此,当你想在一个脚本中改变文件的名字,你只要做一次。 7.2.2. if/then/elif/else结构 7.2.2.1. 概要 这是 if 语句的完全形式: if TEST-COMMANDS; then CONSEQUENT-COMMANDS; elif MORE-TEST-COMMANDS; then MORE-CONSEQUENT-COMMANDS; else ALTERNATE-CONSEQUENT-COMMANDS; fi TEST-COMMANDS 内容执行完后,如果它的返回状态是零,那么就执行 CONSEQUENT-COMMANDS 。如果 TEST-COMMANDS 返回一个非零状态,每个 elif 依次执行,相应的 MORE-CONSEQUENT-COMMANDS 就执行,然后命令结束。如果 else 跟在一个 ALTERNATE-CONSEQUENT-COMMANDS 内容之后,而且在最好的 if 或者 elif 子句的最后命令有一个非零状态,那么 ALTERNATE-CONSEQUENT-COMMANDS 就执行。返回状态就是最后执行的命令的退出状态或者没有条件测试成功就是零。 7.2.2.2. 例子 这是一个你可以把它放到crontab来每天执行的例子: anny /etc/cron.daily> cat disktest.sh #!/bin/bash # This script does a very simple test for checking disk space. space=`df -h | awk '{print $5}' | grep % | grep -v Use | sort -n | tail -1 | cut -d "%" -f1 -` alertvalue="80" if [ "$space" -ge "$alertvalue" ]; then echo "At least one of my disks is nearly full!" | mail -s "daily diskcheck" root else echo "Disk space normal" | mail -s "daily diskcheck" root fi 7.2.3. if嵌套语句 在 if 语句里面,你可以使用另外一个 if 语句。只要你能逻辑管理你就可以使用多层嵌套。 以下是一个测试闰年的例子: anny ~/testdir> cat testleap.sh #!/bin/bash # This script will test if we're in a leap year or not. year=`date +%Y` if [ $[$year % 400] -eq "0" ]; then echo "This is a leap year. February has 29 days." elif [ $[$year % 4] -eq 0 ]; then if [ $[$year % 100] -ne 0 ]; then echo "This is a leap year, February has 29 days." else echo "This is not a leap year. February has 28 days." fi else echo "This is not a leap year. February has 28 days." fi anny ~/testdir> date Tue Jan 14 20:37:55 CET 2003 anny ~/testdir> testleap.sh This is not a leap year. 7.2.4. 布尔操作 以上的脚本可以用布尔操作符 “AND(&&)” 和 “OR(||)” 来缩短。 图 7.2. 使用布尔操作符的例子 year=`date +%Y`; if (( ("$year" % 400) == "0" )) || (( ("$year" % 4 == "0") && ("$year" % 100 != "0") )); then echo "this is a leap year."; else echo "not a leap year"; fi 我们使用双括号来测试一个数学表达式,见 第 3.4.6 节 “算术扩展”。和使用 let 语句是一样的。如果使用类似 $[$year % 400],可能你会对尖括号的使用感到迷惑,因为在这里,尖括号它们自己并不代表一个实际的命令。 在其他一些编辑器中, gvim 是根据文件格式来进行色彩显示的其中之一;这些编辑器在发现代码中的错误时候非常有用。 7.2.5. 使用exit语句和if 我们已经在 第 7.2.1.3 节 “测试参数的数量” 简要的看到了 exit 语句。它使整个脚本中止运行。最常使用于来自用户输入的不正确请求,比如一条语句没有成功运行或者某些其他错误发生。 exit 语句可以带一个可选参数。参数是一个整数退出状态码,储存在 $? 中的返回给父进程的退出状态码。 0参数意味着脚本成功运行完毕。程序员会用其他值来给父进程传递不同的消息,所以根据子进程的成功或者失败,父进程采取不同的动作。如果没有参数给 exit 语句,父shell使用 $? 变量的现存值。 下面是一个和 penguin.sh 脚本相似的例子,会对 feed.sh 传回一个退出状态: anny ~/testdir> cat penguin.sh #!/bin/bash # This script lets you present different menus to Tux. He will only be happy # when given a fish. We've also added a dolphin and (presumably) a camel. if [ "$menu" == "fish" ]; then if [ "$animal" == "penguin" ]; then echo "Hmmmmmm fish... Tux happy!" elif [ "$animal" == "dolphin" ]; then echo "Pweetpeettreetppeterdepweet!" else echo "*prrrrrrrt*" fi else if [ "$animal" == "penguin" ]; then echo "Tux don't like that. Tux wants fish!" exit 1 elif [ "$animal" == "dolphin" ]; then echo "Pweepwishpeeterdepweet!" exit 2 else echo "Will you read this sign?!" exit 3 fi fi 这个脚本被下面那个输出变量 menu 和 animal 的脚本调用: anny ~/testdir> cat feed.sh #!/bin/bash # This script acts upon the exit status given by penguin.sh export menu="$1" export animal="$2" feed="/nethome/anny/testdir/penguin.sh" $feed $menu $animal case $? in 1) echo "Guard: You'd better give'm a fish, less they get violent..." ;; 2) echo "Guard: It's because of people like you that they are leaving earth all the time..." ;; 3) echo "Guard: Buy the food that the Zoo provides for the animals, you ***, how do you think we survive?" ;; *) echo "Guard: Don't forget the guide!" ;; esac anny ~/testdir> ./feed.sh apple penguin Tux don't like that. Tux wants fish! Guard: You'd better give'm a fish, less they get violent... 就像你看到的,退出状态码可以自由选择。退出命令通常有一系列预定义码;请见程序员手册得到每个命令的更多信息。
» 相关连接:
|
» 本栏目最新帖:
» 网站最新帖:
» 精华帖:
» 热点帖:
|