Bash条件判断
每个完整并且合理的程序语言都具有条件判断的功能,并且可以根据条件测试的结果做下一步的处理。Bash有test命令、各种中括号和圆括号操作,和if/then结构。
if/then结构用来判断命令列表的退出状态码是否为0。
有一个专有命令[ (左中括号,特殊字符)。这个命令与test命令等价,并且出于效率上的考虑,这是一个内建命令。这个命令把它的参数作为比较表达式或者作为文件测试,并且根据比较的结果来返回一个退出状态码(0 表示真,1表示假)。
if [ 0 ] echo "0 is true." echo "0 is false." # 0 is true.
在版本2.02的Bash中,引入了[[ ... ]]扩展测试命令,因为这种表现形式可能对某些语言的程序员来说更容易熟悉一些。
注意:[[是一个关键字,并不是一个命令。
[[ 1 3 ]] echo $?
Bash把[[ $a -lt $b ]]看作一个单独的元素,并且返回一个退出状态码。(( ... ))和let ...结构也能够返回退出状态码,当它们所测试的算术表达式的结果为非零的时候,将会返回退出状态码0。这些算术扩展结构被用来做算术比较。
$ let "1 2" $ echo $? $ (( 0 1 )) $ echo $?
if命令能够测试任何命令,并不仅仅是中括号中的条件。
cmp a b /dev/null echo $? # 2 if cmp a b /dev/null # 禁止输出. then echo "Files a and b are identical." else echo "Files a and b differ." # 非常有用的"if-grep"结构: if grep -q bash /etc/profile then echo "File contains at least one occurrence of Bash." word=Linux letter_sequence=inu if echo "$word" | grep -q "$letter_sequence" # "-q" 选项是用来禁止输出的. echo "$letter_sequence found in $word" echo "$letter_sequence not found in $word" if COMMAND_WHOSE_EXIT_STATUS_IS_0_UNLESS_ERROR_OCCURRED then echo "Command succeeded." else echo "Command failed."
条件判断主要判断的是条件是否为真或者假。那么,在什么情况下才为真呢?
# 0 为真 if [ 0 ] echo "0 is true." echo "0 is false." # 1 为真 if [ 1 ] echo "1 is true." echo "1 is false." # -1 为真 if [ -1 ] echo "-1 is true." echo "-1 is false." # NULL 为假 if [ ] echo "NULL is true." echo "NULL is false." # 随便的一串字符为真 if [ xyz ] echo "Random string is true." echo "Random string is false." # 未初始化的变量为假 if [ $xyz ] echo "Uninitialized variable is true." echo "Uninitialized variable is false." # 更加正规的条件检查 if [ -n "$xyz" ] echo "Uninitialized variable is true." echo "Uninitialized variable is false." xyz= # 初始化了, 但是赋null值 # null变量为假 if [ -n "$xyz" ] echo "Null variable is true." echo "Null variable is false." # "false" 为真 if [ "false" ] echo "\"false\" is true." echo "\"false\" is false." # 再来一个, 未初始化的变量 # "$false" 为假 if [ "$false" ] echo "\"\$false\" is true." echo "\"\$false\" is false."
[ 这个命令与test命令等价,把它的参数作为比较表达式或者作为文件测试,并且根据比较的结果来返回一个退出状态码(0 表示真,1表示假),如果参数为确定的一个值或者有初始化,则退出状态码为0;否者为空值或者未初始化,则为1。上面例子也可以通过状态码来验证:
$ [ 0 ] ; echo $? $ [ 1 ] ; echo $? $ [ -1 ] ; echo $? $ [ ] ; echo $? $ [ xyz ] ; echo $? $ [ $xyz ] ; echo $? $ [ -n "$xyz" ] ; echo $? $ xyz= ; [ -n "$xyz" ] ; echo $? $ [ "false" ] ; echo $? $ [ "$false" ] ; echo $?
如果if和then在条件判断的同一行上的话,必须使用分号来结束if表达式。if和then都是关键字,关键字(或者命令)如果作为表达式的开头,并且如果想在同一行上再写一个新的表达式的话,那么必须使用分号来结束上一句表达式。
if语句里还可以加上elif分支,elif是else if的缩写形式,作用是在外部的判断结构中再嵌入一个内部的if/then结构。
if [ condition1 ] command1 command2 command3 elif [ condition2 ] # 与else if一样 command4 command5 default-command
if test condition-true结构与if [ condition-true ]完全相同. 就像我们前面所看到的,左中括号是调用test命令的标识,而关闭条件判断用的的右中括号在if/test结构中并不是严格必需的,但是在Bash的新版本中必须要求使用。
注意: test命令在Bash中是内建命令,用来测试文件类型,或者用来比较字符串。因此,在Bash脚本中,test命令并不会调用外部的/usr/bin/test中的test命令,这是sh-utils工具包中的一部分。同样的,[也并不会调用/usr/bin/[,这是/usr/bin/test的符号链接。
下面测试type命令:
bash$ type test test is a shell builtin bash$ type [ [ is a shell builtin bash$ type [[ [[ is a shell keyword bash$ type ]] ]] is a shell keyword bash$ type ] bash: type: ]: not found
test、/usr/bin/test、[ ]和/usr/bin/[都是等价命令。
if test -z "$1" echo "No command-line arguments." echo "First command-line argument is $1." if /usr/bin/test -z "$1" echo "No command-line arguments." echo "First command-line argument is $1." if [ -z "$1" ] # if [ -z "$1" 应该能够运行,但是Bash报错, 提示缺少关闭条件测试的右中括号 echo "No command-line arguments." echo "First command-line argument is $1." if /usr/bin/[ -z "$1" ] # if /usr/bin/[ -z "$1" # 能够工作,但是还是给出一个错误消息。注意:在版本3.x的Bash中, 这个bug已经被修正了 echo "No command-line arguments." echo "First command-line argument is $1."
[[ ]]结构比[ ]结构更加通用。这是一个扩展的test命令,是从ksh88中引进的。在[[和]]之间所有的字符都不会发生文件名扩展或者单词分割,但是会发生参数扩展和命令替换。
file=/etc/passwd if [[ -e $file ]] echo "Password file exists."
使用[[ ... ]]条件判断结构而不是[ ... ],能够防止脚本中的许多逻辑错误。比如 、||、 和 操作符能够正常存在于[[ ]]条件判断结构中,,但是如果出现在[ ]结构中的话,会报错。
在if后面也不一定非得是test命令或者是用于条件判断的中括号结构。
dir=/home/bozo if cd "$dir" 2 /dev/null; then # "2 /dev/null" 会隐藏错误信息. echo "Now in $dir." echo "Cant change to $dir."
“if COMMAND”结构将会返回COMMAND的退出状态码。与此相似,在中括号中的条件判断也不一定非得要if不可,也可以使用列表结构。
var1=20 var2=22 [ "$var1" -ne "$var2" ] echo "$var1 is not equal to $var2" home=/home/bozo [ -d "$home" ] || echo "$home directory does not exist."
(( ))结构扩展并计算一个算术表达式的值。如果表达式的结果为0,那么返回的退出状态码为1,或者是”假”。而一个非零值的表达式所返回的退出状态码将为0,或者是”true”。这种情况和先前所讨论的test命令和[ ]结构的行为正好相反。
#!/bin/bash # 算术测试. # (( ... ))结构可以用来计算并测试算术表达式的结果. # 退出状态将会与[ ... ]结构完全相反! (( 0 )) echo "Exit status of \"(( 0 ))\" is $?." # 1 (( 1 )) echo "Exit status of \"(( 1 ))\" is $?." # 0 (( 5 4 )) # 真 echo "Exit status of \"(( 5 4 ))\" is $?." # 0 (( 5 9 )) # 假 echo "Exit status of \"(( 5 9 ))\" is $?." # 1 (( 5 - 5 )) # 0 echo "Exit status of \"(( 5 - 5 ))\" is $?." # 1 (( 5 / 4 )) # 除法也可以. echo "Exit status of \"(( 5 / 4 ))\" is $?." # 0 (( 1 / 2 )) # 除法的计算结果 1. echo "Exit status of \"(( 1 / 2 ))\" is $?." # 截取之后的结果为 0. (( 1 / 0 )) 2 /dev/null # 除数为0, 非法计算. # ^^^^^^^^^^^ echo "Exit status of \"(( 1 / 0 ))\" is $?." # 1 # "2 /dev/null"起了什么作用? # 如果这句被删除会怎样? (( 1 / 0 )) echo "Exit status of \"(( 1 / 0 ))\" is $?." # 2 exit 0
就如文章开头所言,(( ... ))和let ...结构也能够返回退出状态码,当它们所测试的算术表达式的结果为非零的时候,将会返回退出状态码0。
测试操作符文件测试操作符:
-t 文件(描述符)被关联到一个终端设备上。这个测试选项一般被用来检测脚本中的stdin([ -t 0 ]) 或者stdout([ -t 1 ])是否来自于一个终端. -r 文件是否具有可读权限(指的是正在运行这个测试命令的用户是否具有读权限) -w 文件是否具有可写权限(指的是正在运行这个测试命令的用户是否具有写权限) -x 文件是否具有可执行权限(指的是正在运行这个测试命令的用户是否具有可执行权限) -g set-group-id(sgid)标记被设置到文件或目录上。如果目录具有sgid标记的话, 那么在这个目录下所创建的文件将属于拥有这个目录的用户组,而不必是创建这个文件的用户组. 这个特性对于在一个工作组中共享目录非常有用。 -u set-user-id (suid)标记被设置到文件上。如果一个root用户所拥有的二进制可执行文件设置了set-user-id标记位的话,那么普通用户也会以root权限来运行这个文件。这对于需要访问系统硬件的执行程序非常有用。如果没有suid标志的话,这些二进制执行程序是不能够被非root用户调用的。对于设置了suid标志的文件,在它的权限列中将会以s表示。 -k 设置粘贴位。粘贴位设置在目录中,它将限制写权限,在它们的权限标记列中将会显示t。如果用户并不拥有这个设置了粘贴位的目录,但是他在这个目录下具有写权限,那么这个用户只能在这个目录下删除自己所拥有的文件。这将有效的防止用户在一个公共目录中不慎覆盖或者删除别人的文件,比如说/tmp目录。 -O 判断你是否是文件的拥有者 -G 文件的group-id是否与你的相同 -N 从文件上一次被读取到现在为止,文件是否被修改过 f1 -nt f2 文件f1比文件f2新 f1 -ot f2 文件f1比文件f2旧 f1 -ef f2 文件f1和文件f2是相同文件的硬链接 ! 反转上边所有测试的结果(如果没给出条件,那么返回真)。
二元比较操作符,用来比较两个变量或数字:
小于,按照ASCII字符进行排序 if [[ "$a" "$b" ]] if [ "$a" \ "$b" ] 注意使用在[ ]结构中的时候需要被转义。 大于,按照ASCII字符进行排序 if [[ "$a" "$b" ]] if [ "$a" \ "$b" ] 注意使用在[ ]结构中的时候需要被转义。 -z 字符串为”null”,意思就是字符串长度为零 -n 字符串不为”null”,当-n使用在中括号中进行条件测试的时候,必须要把字符串用双引号引用起来。
注意:==比较操作符在双中括号对和单中括号对中的行为是不同的。
if [[ $a == z* ]] # 如果$a以"z"开头(模式匹配),那么结果将为真 then echo true else echo false if [[ $a == "z*" ]] # 如果$a与z*相等,就是字面意思完全一样,那么结果为真。 then echo true else echo false if [ $a == z* ] # 如果$a与z*相等,就是字面意思完全一样,那么结果为真。不存在模式匹配 then echo true else echo false if [ "$a" == "z*" ] # 如果$a与z*相等,就是字面意思完全一样,那么结果为真。 then echo true else echo false
检查字符串是否为null,有以下几种方法:
#!/bin/bash # str-test.sh: 检查null字符串和未引用的字符串 if [ -n $string1 ] # $string1 没有被声明和初始化 echo "String \"string1\" is not null." else echo "String \"string1\" is null." if [ -n "$string1" ] # 这次$string1被引号扩起来了. echo "String \"string1\" is not null." else echo "String \"string1\" is null." if [ $string1 ] # 这次,就一个$string1,什么都不加 echo "String \"string1\" is not null." else echo "String \"string1\" is null." # [ ] 测试操作符能够独立检查string是否为null,然而,使用("$string1")是一种非常好的习惯 # if [ $string1 ] 只有一个参数 "]" # if [ "$string1" ] 有两个参数,一个是空的"$string1",另一个是"]" string1=initialized if [ $string1 ] # 再来,还是只有$string1,什么都不加 echo "String \"string1\" is not null." else echo "String \"string1\" is null." # 这个例子运行还是给出了正确的结果,但是使用引用的("$string1")还是更好一些 string1="a = b" if [ $string1 ] # 再来,还是只有$string1,什么都不加 echo "String \"string1\" is not null." else echo "String \"string1\" is null." # 未引用的"$string1",这回给出了错误的结果 exit 0
本篇文章介绍了如何使用Bash的条件判断,涉及到test命令、各种中括号和圆括号操作,以及if/then结构。需要知道,test、/usr/bin/test、[ ]和/usr/bin/[都是等价命令,使用type命令可以分区内建命令和关键字。另外,需要区分单中括号和双中括号以及双圆括号的含义是不同的。
单中括号[,与test命令等价,是个内建命令 双中括号[[,是扩展测试命令,是个关键字 双圆括号(()),是根据算术表达式运行结果来返回不同状态码使用[[ ... ]]条件判断结构而不是[ ... ],能够防止脚本中的许多逻辑错误。比如 、||、 和 操作符能够正常存在于[[ ]]条件判断结构中,,但是如果出现在[ ]结构中的话,会报错。
Linux模拟实现【简易版bash】 Linux 系统主要分为 内核(kernel) 和 外壳(shell),普通用户是无法接触到内核的,因此实际在进行操作时是在和外壳程序打交道,在 shell 外壳之上存在 命令行解释器(bash),负责接收并执行用户输入的指令,本文模拟实现的就是一个 简易版命令行解释器
Shell脚本的常用执行方式、bash 和 sh 的关系、子shell、Centos 默认的解析器是 bash、Linux 提供的 Shell 解析器、Shell 概述、Shell 脚本入门 采用 bash 或 sh+脚本的相对路径或绝对路径(不用赋予脚本+x 权限)、采用输入脚本的绝对路径或相对路径执行脚本(必须具有可执行权限+x)、在脚本的路径前加上“.”或者 source(了解)原因: 前两种方式都是在当前 shell 中打开一个子 shell 来执行脚本内容,当脚本内容结束,则 子 shell 关闭,回到父 shell 中。第三种,也就是使用在脚本路径前加“.”或者 source 的方式,`可以使脚本内容在当前 shell 里执行,而无需打开子 shell!`这也是为什么我们每次要修改完
Linux Shell编程(2) - Bash 变量 1. Bash 变量的命名规则 变量名只能包含字母、数字、下划线 变量名不能以数字作为开头 变量名区分大小写 变量名长度不超过255个字符 变量名在有效范围内必须唯一
雨客 微博@JavaChen,这里的所有博客文章来自http://blog.javachen.com/。
相关文章
- 判断一个非主键字段是否存在数据的三次改进
- case when 判断_sqlservercase用法
- 32位int取值范围_正则表达式判断是否是int32
- 使用函数判断三角形(10分)【简单判断 IF 】
- 图片移动并进行边界判断详解手机开发
- 判断传入的参数是否为数字详解编程语言
- java判断字符串中是否含有汉字详解编程语言
- SQL 条件 判断 select case as详解编程语言
- c:if标签多条件的逻辑判断详解编程语言
- 利用Oracle IF函数实现复杂条件判断(oracleif函数)
- Linux系统下的条件判断(linuxforif)
- MySQL存储函数IF:实现条件判断的利器(mysql存储函数if)
- 字符Linux 条件判断:处理空字符串(linuxif判断空)
- Oracle中字符串比较:判断是否相等(oracle字符判断相等)
- 判断Linux中如何实现多个条件的判断(linuxif多个条件)
- 判断Linux下多条件判断的实现(linuxif多个条件)
- 判断Linux中如何结合多个if条件判断(linuxif多个条件)
- 使用MySQL的IF函数进行多条件判断(mysql的if函数)
- MySQL中使用IF函数实现条件判断和计算(mysql 中使用if)
- MySQL中的条件判断语句详解(mysql中判断条件语句)
- MySQL插入记录前需先判断数据是否存在(mysql不存在插入存在)
- Oracle条件判断一步搞定(oracle些判断语句)
- 语句利用Oracle构建复杂条件判断多个If语句讲解(oracle使用多个if)
- Oracle条件判断实现数据安全管理(Oracle写条件判断)
- 大小写在Oracle中实现字母大小写判断(oracle中判断字母)
- oracle数据库中的条件判断语句简介(oracle 中写判断)
- 语句利用Oracle的IF条件语句实现多条件判断(oracle中if多条件)
- php中经典方法实现判断多维数组是否为空
- JavaScript判断DOM何时加载完毕的技巧
- js代码判断浏览器种类IE、FF、Opera、Safari、chrome及版本