主要内容
条件测试
shell终端中的条件测试一般包括文件类型检测和值对比,条件测试通过test命令进行。
例如:检测文件夹或者文件是否存在,字符串是否相等,或者字符串是否为空等等。
文件检测
通过-f(file)参数检测一般文件
1 2 3 4 5 6 7 |
#创建文件testfile [normal@study ~]$ touch testfile #检测文件是否存在 [normal@study ~]$ test -f testfile #如果文件存在,则退出状态码为0,否则状态码为1 [normal@study ~]$ echo $? 0 |
文件是否可写
1 2 3 |
[normal@study ~]$ test -w testfile [normal@study ~]$ echo $? 0 |
文件是否可执行
1 2 3 |
[normal@study ~]$ test -x /usr/bin/ls [normal@study ~]$ echo $? 0 |
目录检测
目录的检测使用-d(directory)参数
1 2 3 4 |
[normal@study ~]$ mkdir testdir [normal@study ~]$ test -d testdir [normal@study ~]$ echo $? 0 |
字符串比较
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
[normal@study ~]$ test "hello" = "world" [normal@study ~]$ echo $? 1 [normal@study ~]$ test "hello" != "world" [normal@study ~]$ echo $? 0 #字符串长度不为0 [normal@study ~]$ test -n "hello" [normal@study ~]$ echo $? 0 #字符串长度为0 [normal@study ~]$ test -z "hello" #由于字符串hello不为0,因此退出码是1 [normal@study ~]$ echo $? 1 |
整数比较
1 2 3 4 5 6 7 8 |
[normal@study ~]$ declare -i var1=10 [normal@study ~]$ declare -i var2=20 [normal@study ~]$ test ${var1} = ${var2} [normal@study ~]$ echo $? 1 [normal@study ~]$ test ${var1} != ${var2} [normal@study ~]$ echo $? 0 |
除了相等性比较外,整数还可以进行>(-gt),<(-lt),>=(-ge),<=(-le)比较。
上面的例子列举的是比较常用的操作,更多操作可参看test的manpage。
控制结构
shell的控制结构包括:if、when、while、until、case等。
分支:if
if用于根据特定条件执行不同的操作。它的语法如下:
1 2 3 4 5 6 7 |
if condition; then #do something elif condition2; then #other thing else #statement fi |
condition后面的分号“;”可以没有,这样then就要写到下一行。
if 控制结构往往都是和前面的条件测试一起使用,例如:
1 2 3 4 5 6 7 8 |
#!/bin/sh if test -f test.c; then echo "file exist" elif test -d testdir; then echo "testdir is a directory" else echo "file does not exists" fi |
下面是另一种更常见的写法:
1 2 3 4 5 6 7 8 |
#!/bin/sh if [ -f test.c ]; then echo "file exists" elif [ -d testdir ]; then echo "testdir is a directory" else echo "file does not exist" fi |
使用“[ -f test.c ]”代替 test -f test.c,不过需要注意的是,[]里面的命令两边都要至少留一个空格,否则命令会出错。
一个简单的例子
文件查找,调用系统的find命令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#!/bin/sh searchPath=$1 searchFileName=$2 #if [ $# = 0 -o $# = 1 ]; then #如果参数个数等于0或者等于1 if [ $# -lt 2 ]; then #如果参数个数小于2 echo "usage: <serach path> <serach name>" exit 1 fi #如果目录存在 if [ -d $1 ]; then find $searchPath -name $searchFileName 2>/dev/null else echo "direcotry ${searchPath} doesn't exist" exit 1 fi |
另外,当使用test进行字符串比较(小于/大于)的时候,会出现意想不到的问题:
1 2 3 4 5 6 7 8 9 10 11 |
#!/bin/bash val1=baseball val2=hockey if [ $val1 > $val2 ] then echo "$val1 is greater than $val2" else echo "$val1 is less than $val2" fi |
当运行脚本,会输出baseball is greater than hockey。实际上这是错误的结果,原因在于,在比较字符串的时候,>符号被shell当作输出重定向符号处理,但却没有给出任何提示。正确的做法是使用\符号把大于符号或者小于符号转义:
1 2 3 4 5 6 7 8 9 10 11 |
#!/bin/bash val1=baseball val2=hockey if [ $val1 \> $val2 ] then echo "$val1 is greater than $val2" else echo "$val1 is less than $val2" fi |
逻辑与(&&)和逻辑或(||)
通常在使用if的时候,需要判断多个条件或者某个条件是否成立的情况,这个时候就需要使用逻辑与和逻辑或
这两个操作符的使用也是非常简单的,和其他语言上的操作符基本一致
语法:
1 2 |
statement1 && statement2 && statement3 statement1 || statement2 || statement3 |
使用语句块
如果你希望在某些只能使用单个语句的地方使用多条语句,就可以把多条语句使用{}括起来,这样shell会把括号中的多条语句当做一个整体处理。例如:
1 2 3 4 5 |
if [ -d dirname ] && { statement1 statement2 statement3 } |
使用双引号防止用户的错误输入
我们永远不要相信用户的输入,也就是说,用户输入的数据并不一定是我们期待的数据,例如:用户直接按回车,什么也不输入。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#!/bin/sh echo "is it morning? Please answer yes or no" read timeofday if [ $timeofday = "yes" ]; then echo "Good morning" elif [ $timeofday = "no" ]; then echo "Good afternoon" else echo "Sorry $timeofday not recognized. Enter yes or no" exit 1 fi exit 0 |
很明显,我们期待用户输入有价值的数据,但是如果用户直接按下回车,timeofday变量就是一个空的数据,这样,shell就会执行错误,即语句变成:
1 |
if [ = "yes" ]; then |
为了防止这样的错误数据,只需要使用双引号把变量括起来:
1 |
if [ "$timeofday" = "yes" ]; then |
在if语句中使用双圆括号(( ))和双方括号[[ ]]
通过使用双圆括号和双方括号,可以在if语句中使用增强的算数运算和字符串比较。
双圆括号支持的算术运算符:
val++、val–、++val、–val、!(取反)、~(位取反)、**(求幂)、<<(左移)、>>(右移)、&(按位与)、|(按位或)、&&(逻辑与)、||(逻辑或)。
简单的例子:
1 2 3 4 5 6 7 8 9 10 |
#!/bin/bash # using double parenthesis # val1=10 # if (( $val1 ** 2 > 90 )) then (( val2 = $val1 ** 2 )) echo "The square of $val1 is $val2" fi |
而双方括号主要增强的是字符串的正则表达式支持,例如:
1 2 3 4 5 6 7 8 9 |
#!/bin/bash # using pattern matching # if [[ $USER == r* ]] then echo "Hello $USER" else echo "Sorry, I do not know you" fi |
for循环:
for循环语法:
1 2 3 4 |
for variable in values do statements done |
一个简单例子, 列出当前目录的所有内容:
1 2 3 4 5 |
#!/bin/sh for file in * do echo ${file} done |
另一个例子:
1 2 3 4 5 6 7 8 9 |
#!/bin/sh for var in one two three do echo $var done #程序输出: #one #two #three |
在循环中结合bash命令使用
1 2 3 4 5 6 |
for file in `ls P*`; do #使用``执行外部命令 echo ${file} done #输出结果 #Pictures: #Public: |
除了可以使用上面的方式执行外部命令外,还可以使用$(), 他们的效果是一样的
1 |
for file in $(ls P*); do |
c-style for循环
新版本的shell支持类c的for循环,类c的for循环需要配合双圆括号使用,如下:
1 2 3 4 5 6 |
#!/bin/bash for (( i=1; i <= 10; i++ )) do echo "The next number is $i" done |
和c语言的for循环一样,它可以同时使用多个变量:
1 2 3 4 5 6 |
#!/bin/bash for (( a=1, b=10; a <= 10; a++, b-- )) do echo "$a - $b" done |
while循环
语法:
1 2 3 |
while condition; do statements done |
一般在不知道需要循环执行多少次的时候,使用while循环。
除了while循环外,还有do…while循环,do…while循环中至少执行一次循环体。
while允许用户设立多个条件测试,例如:
1 2 3 4 5 6 7 8 |
#!/bin/bash var1=10 while echo $var1 [ $var1 -ge 0 ] do echo "This is inside the loop" var1=$[ $var1 - 1 ] done |
until循环
until循环和while循环差不多,和while循环不同的是,until反复执行直到条件为真,而while循环则条件为真时一直循环,until类似于其他语言的do…while循环。
语法:
1 2 3 |
until condition; do statements done |
处理循环结构中的数据输出
我们可以把循环体中的输出重定向到其他位置,例如文件中。只需要在done
关键字后面添加重定向操作符即可。
1 2 3 4 5 6 7 8 |
#!/bin/bash # redirecting the for output to a file for (( a = 1; a < 10; a++ )) do echo "The number is $a" done > test.txt #把输出重定向到文件test.txt中 echo "The command is finished." |
其他的循环的重定向例如while,until的使用方法一样。
其实除了重定向,还可以使用管道处理循环中的输出,使用方法和重定向类似。
跳出循环
和其他语言一样,shell也可以根据条件跳出循环,使用break和continue命令即可。
break用于跳出循环,不再执行循环中的代码,而continue则用于跳出当前循环,继续执行下一次循环。
case分支
case分支类似于其他语言的switch结构,但shell中只有case没有switch。
语法:
1 2 3 4 |
case variable in pattern [ | pattern] ) statements;; pattern [ | pattern] ) statements;; esac |
需要注意:每一个模式行都是使用双分号结尾“;;”
一个简单的例子:
1 2 3 4 5 6 7 8 9 10 |
#!/bin/sh echo "Is it morning ? Please answer yes or no" read timeofday case "$timeofday" in yes | y | Yes | YES ) echo "Good morning";; n* | N* ) echo "Good Afternoon";; * ) echo "Sorry, answer not recognized";; esac |
使用正则匹配
除了管道符号外,case模式还可以使用正则匹配
1 2 3 4 5 6 7 8 9 10 |
#!/bin/sh echo "Is it morning ? Please answer yes or no" read timeofday case "$timeofday" in [yY] | [Ee] | [Ss] ) echo "Good morning";; [nN]* ) echo "Good Afternoon";; * ) echo "Sorry, answer not recognized";; esac |
转载请注明:Pure nonsense » shell程序设计(三)条件测试和控制结构