十年运维系列之基础篇 - Linux
作者:曾林
联系:1494445739@qq.com
网站:www.jplatformx.com
版权:文章未经同意请勿转载
一、使用if语句
通过shell,我们可以来写出这样的一个使用if语句的shell脚本片段。如下所示:
#!/bin/bash # test "if" statementx=5if [ $x = 5 ]; thenecho "x equals 5" elseecho "x doesn't equals 5" fi
或者可以直接在命令行中输入以上代码(略有简化),如下图所示:
if语句的语法格式如下:
if commands; thencommands [elif commands; thencommands] [elsecommands] if
在这个语法格式中,“command”可以是一组命令。乍看上去可能会有些迷惑。在去除这个迷惑之前,我们必须要先了解一下shell如何判断一个命令的成功与失败。
二、退出状态
命令(包括我们编写的shell脚本和shell函数)在执行完毕后,会向操作系统发送一个值,称之为“退出状态”。这个值是一个0~255的整数,用来指示命令执行成功还是失败。按照惯例,数值0表示执行成功,其他的数值表示执行失败。shell提供了一个可以用来检测退出状态的参数。这个参数就是$?。如下图所示:
在这个例子中,我们两次执行了ls命令。第一次,命令执行成功,如果显示参数“$?”的值,可以看到值是0.第二次执行ls命令时,产生了一个错误,再次显示“$?”的值,这次值是2,表示这个命令遇到了一个错误。有些命令使用不同的退出值来诊断错误,而需要命令执行失败时,只是简单地退出并发送数字1.man手册中经常会包括一个标题为“Exit Status”的段落,它描述使用的代码。数字0总是表示执行成功。
shell提供了2个非常简单的内置命令,它们不做任何事情,除了以一个0或1退出状态来终止执行。“true”命令总是表示执行成功,而“false”命令总是表示执行失败。如下图所示:
我们可以用这两个命令来查看if语句是如何工作的。if语句真正做的事情是评估命令的成功或失败。
当在if后面的命令执行成功时,命令echo "it's true."会被执行,而当在if后面的命令执行失败时,该命令则不执行。如果在if后面有一系列的命令,那么则根据最后一个命令的执行结果来进行评估。如下图所示:
三、使用test命令
目前为止,经常和if一起使用的命令是test。test命令会执行各种检查和比较。这个命令有两种等价的形式:
test expression
以及更加流行的
[ expression ]
这里的expression是一个表达式,其结果是true或false。当这个表达式为true时,test命令会返回一个0退出状态;当表达式为false时,test命令的退出状态为1。
-
文件表达式(expression)
下表中的表达式展示的是有关文件的表达式。这些文件表达式用来评估文件的状态。
文件表达式 | 成为true的条件 |
file1 -ef file2 | file1和file2拥有相同的信息节点编号(这两个文件通过硬链接指向同一个文件) |
file1 -nt file2 | file1比file2新 |
file1 -ot file2 | file1比file2旧 |
-b file | file存在并且是一个块(设备)文件 |
-c file | file存在并且是一个字符(设备)文件 |
-d file | file存在并且是一个目录 |
-e file | file存在 |
-f file | file存在并且是一个普通文件 |
-g file | file存在并且设置了组ID |
-G file | file存在并且属于有效组ID |
-k file | file存在并且有“粘滞位(sticky bit)属性” |
-L file | file存在并且是一个符号链接 |
-O file | file存在并且属于有效用户ID |
-p file | file存在并且是一个命名管道 |
-r file | file存在并且可读(有效用户有可读权限) |
-s file | file存在并且其长度大于0 |
-S file | file存在并且是一个网络套接字 |
-t fd | fd是一个定向到终端/从终端定向的文件描述符,可以用来确定标准输入/输出/错误是否被重定向 |
-u file | file存在并且设置了setuid位 |
-w file | file存在并且可写(有效用户拥有可写权限) |
-x file | file存在并且可执行(有效用户拥有执行/搜索权限) |
下面代码展示了一个使用文件表达式的例子:
#!/bin/bash# test-file: Evaluate the status of a fileFILE=~/.bashrcif [ -e "$FILE" ]; thenif [ -f "$FILE" ]; thenecho "$FILE is a regular file."fi if [ -d "$FILE" ]; thenecho "$FILE is a directory."fi if [ -r "$FILE" ]; thenecho "$FILE is readable."fi if [ -w "$FILE" ]; thenecho "$FILE is writable."fi if [ -x "$FILE" ]; thenecho "$FILE is executable/searchable."fi elseecho "$FILE does not exist"exit 1 fiexit
关于上面的脚本,需要注意两个有趣的地方。首先,要注意$FILE在表达式内是如何被引用的。尽管引号不是必需的,但是这可以防范参数为空的情况。如果$FILE的参数扩展产生一个空值,将导致一个错误(操作符会被解释为非空的字符串,而不是操作符)。用引号把参数括起来可以确保操作符后面总是跟随一个字符串,即使字符串为空。其次,注意脚本末尾的exit命令。这个exit命令接受一个单独的可选参数,它将称为脚本的退出状态。当不传递参数时,退出状态默认为0。以这种方法使用exit命令,当$FILE扩展为一个不存在的文件名时,可以允许脚本提示失败。这个exit命令出现在脚本的最后一行。这样,当脚本执行到最后时,不管怎么样,默认情况下它将以退出状态0终止。
类似地,通过在return命令中包含一个整数参数,shell函数可以返回一个退出状态。如果要将上面的脚本转换为一个shell函数,从而能够在一个更大的程序中使用,可以将exit命令替换为return命令,并得到想要的行为。
四、字符串表达式
下列表达式用来测试字符串的操作。
表达式 | 称为true的条件 |
string | string不为空 |
-n string | string的长度大于0 |
-z string | string的长度等于0 |
string1 = string2 string1 == string2 | string1和string2相等。单等号和双等号都可以使用,但是双等号使用的更多。要注意在使用等号和不等于号的时候,需要操作符两边加空格。否则执行结果不是你想象 |
string1 > string2 | 在排序时,string1在string2之后 |
string1 < string2 | 在排序时,string1在string2之前 |
string1 != string2 | string1和string2不相等 |
警告:在使用test命令时,“>”和“<”运算符必须用引号括起来(或者是使用反斜杠来进行转义)。如果不这么做,就会被shell解释为重定向操作符,从而造成潜在的破坏性结果。同时注意,尽管bash文档中已经有过声明,排序遵从当前语系的排列规则,但并非如此。在bash 4.0版本以前(包括4.0版本),使用的是ASCII(POSIX)排序方式。
五、整数表达式
下表中的表达式可以用于整数。
表达式 | 成为true的条件 |
integer1 -eq integer2 | integer1和integer2相等 |
integer1 -ne integer2 | integer1和integer2不相等 |
integer1 -le integer2 | integer1小于等于integer2 |
integer1 -lt integer2 | integer1小于integer2 |
integer -gt integer2 | integer1大于integer2 |
integer1 -ge integer2 | integer1大于等于integer2 |
六、更现代的test指令
bash提供了复合命令(()),而不是[](test指令)用来操作整数。该命令支持一套完整的算术计算。
复合指令(())用于执行算术真值测试(arithmetic truth test)。当算术计算的结果是非0值时,则算术真值测试为true。
以下是一个使用(())复合命令来测试算术结果的样例脚本,注意这里使用了小于号、等于号和大于号来测试相等性。在处理整数的时候,这些语法看起来更加的自然。此外,由于(())复合命令只是shell语法的一部分,而非普通的命令,并且只能处理整数。
#!/bin/bash# compound command (()) for arithmetic computingINT=7if [ -z "$INT" ]; thenecho "INT is empty." >&2exit 1 elif (( $INT == 0 )); thenecho "INT equals zero." elif (( $INT < 0 )); thenecho "INT less than zero." elif (( $INT > 0)); thenecho "INT greater than zero." fiif (( $INT % 2 == 0)); thenecho "INT is even." elseecho "INT is odd." fi
七、组合表达式
我们也可以将表达式组合起来,来创建更复杂的计算。表达式是使用逻辑运算符组合起来的。与test命令配套的逻辑运算符有三个,它们是and, or和not。下表展示了逻辑操作符。
Operation | test | (()) |
AND | -a | && |
OR | -o | || |
NOT | ! | ! |
八、控制运算符:另一种方式的分支
bash还提供了两种可以执行分支的控制运算符。“&&”和“||”运算符与上述复合命令中的逻辑运算符类似,语法如下:
command1 && command2 和 command1 || command2
理解这两个运算符是非常重要的。对于“&&”运算符来说,先执行command1,只有在command1执行成功时,command2才能够执行。对于“||”运算符来说,先执行command1,则只有command1执行失败的时候,command2才能够执行。
从实用性考虑,这意味着可以这样做:
mkdir test && cd test
这会创建一个temp目录,并且当这个创建工作执行成功后,当前的工作目录才会更改为temp。只有在第一个mkdir命令执行成功后,才会尝试执行第二个命令。同样,看如下命令:
[ -d temp ] || mkdir temp
这个命令先检测temp目录是否存在,只有当检测失败时,才会创建这个目录。