title: SHELL脚本编程_2
data: 2018-9-19
tags: [SHELL,学习,编程]
categories: [SHELL,学习,编程]
grammar_cjkRuby: true
copyright: true
给出的那些shell脚本里, shell按照命令在脚本中出现的顺序依次进行处理。对顺序操作来说,这已经足够了,因为在这种操作环境下,你想要的就是所有的命令按照正确的顺序执行。然而,并非所有程序都如此操作。许多程序要求对shell脚本中的命令施加一些逻辑流程控制。有一类命令会根据条件使脚本跳过某些命令。这样的命令通常称为结构化命令(structured command)。
使用结构化命令
使用if -then语句
最基本的结构化命令就是 if-then 语句。 if-then 语句有如下格式。
if command
then
commands
fi
bash shell的 if 语句会运行 if 后面的那个命令。如果该命令的退出状态码是 0(该命令成功运行),位于 then 部分的命令就会被执行。如果该命令的退出状态码是其他值, then部分的命令就不会被执行,bash shell会继续执行脚本中的下一个命令。 fi 语句用来表示 if-then语句到此结束。
有些脚本中看到过 if-then 语句的另一种形式:
if command; then
commands
fi
通过把分号放在待求值的命令尾部,就可以将 then 语句放在同一行上了,这样看起来更像其他编程语言中的 if-then 语句。
在 then 部分,你可以使用不止一条命令。可以像在脚本中的其他地方一样在这里列出多条命令。bash shell会将这些命令当成一个块,如果 if 语句行的命令的退出状态值为 0 ,所有的命令都会被执行;如果 if 语句行的命令的退出状态不为 0 ,所有的命令都会被跳过。
if-then-else 语句
在 if-then 语句中,不管命令是否成功执行,你都只有一种选择。如果命令返回一个非零退出状态码,bash shell会继续执行脚本中的下一条命令。在这种情况下,如果能够执行另一组命令就好了。这正是 if-then-else 语句的作用。if-then-else 语句在语句中提供了另外一组命令。
if command
then
commands
else
commands
fi
当 if 语句中的命令返回退出状态码 0 时, then 部分中的命令会被执行,这跟普通的 if-then语句一样。当 if 语句中的命令返回非零退出状态码时,bash shell会执行 else 部分中的命令。
嵌套if
可以直接嵌套if结构,理论上支持多重嵌套,实际上程序员并不会放置超过三重,过多影响代码的逻辑性和可读性。
可以使用 else 部分的另一种形式: elif 。这样就不用再书写多个 if-then 语句了。 elif 使
用另一个 if-then 语句延续 else 部分。
if command1
then
commands
elif command2
then
more commands
fi
在 elif 语句中,紧跟其后的 else 语句属于 elif 代码块。它们并不属于之前的if-then 代码块。
可以继续将多个 elif 语句串起来,形成一个大的 if-then-elif 嵌套组合。
if command1
then
command set 1
elif command2
then
command set 2
elif command3
then
command set 3
elif command4
then
command set 4
fi
test 命令
test 命令提供了在 if-then 语句中测试不同条件的途径。如果 test 命令中列出的条件成立,test 命令就会退出并返回退出状态码 0 。这样 if-then 语句就与其他编程语言中的 if-then 语句以类似的方式工作了。如果条件不成立, test 命令就会退出并返回非零的退出状态码,这使得if-then 语句不会再被执行。test 命令的格式非常简单。
test condition
condition 是 test 命令要测试的一系列参数和值。当用在 if-then 语句中时, test 命令看起来是这样的。
if test condition
then
commands
fi
如果不写 test 命令的 condition 部分,它会以非零的退出状态码退出,并执行 else 语句块。
bash shell提供了另一种条件测试方法,无需在 if-then 语句中声明 test 命令。
if [ condition ]
then
commands
fi
方括号定义了测试条件。注意,第一个方括号之后和第二个方括号之前必须加上一个空格,否则就会报错。
test 命令可以判断三类条件:
- 数值比较
- 字符串比较
- 文件比较
数值比较
使用 test 命令最常见的情形是对两个数值进行比较。下表列出了测试两个值时可用的条件参数。
比较 | 描述 |
---|---|
n1 -eq n2 | 检查 n1 是否与 n2 相等 |
n1 -ge n2 | 检查 n1 是否大于或等于 n2 |
n1 -gt n2 | 检查 n1 是否大于 n2 |
n1 -le n2 | 检查 n1 是否小于或等于 n2 |
n1 -lt n2 | 检查 n1 是否小于 n2 |
n1 -ne n2 | 检查 n1 是否不等于 n2 |
字符串比较
条件测试还允许比较字符串值。比较字符串比较烦琐,你马上就会看到。下表列出了可用的字符串比较功能。
比较 | 描述 |
---|---|
str1 = str2 | 检查 str1 是否和 str2 相同 |
str1 != str2 | 检查 str1 是否和 str2 不同 |
str1 < str2 | 检查 str1 是否比 str2 小 |
str1 > str2 | 检查 str1 是否比 str2 大 |
-n str1 | 检查 str1 的长度是否非0 |
-z str1 | 检查 str1 的长度是否为0 |
字符串相等性
字符串的相等和不等条件不言自明,很容易看出两个字符串值是否相同,字符串不等条件也可以判断两个字符串是否有相同的值。记住,在比较字符串的相等性时,比较测试会将所有的标点和大小写情况都考虑在内。
字符串顺序
要测试一个字符串是否比另一个字符串大就是麻烦的开始。当要开始使用测试条件的大于或小于功能时,就会出现两个经常困扰shell程序员的问题:
- 大于号和小于号必须转义,否则shell会把它们当作重定向符号,把字符串值当作文件名
- 大于和小于顺序和 sort 命令所采用的不同
在编写脚本时,第一条可能会导致一个不易察觉的严重问题。
test 命令和测试表达式使用标准的数学比较符号来表示字符串比较,而用文本代码来表示数值比较。这个细微的特性被很多程序员理解反了。如果你对数值使用了数学运算符号,shell会将它们当成字符串值,可能无法得到正确的结果。
检查字符串大小
-n 和 -z 可以检查一个变量是否含有数据。空的和未初始化的变量会对shell脚本测试造成灾难性的影响。如果不是很确定一个变量的内容,最好在将其用于数值或字符串比较之前先通过 -n 或 -z 来测试一下变量是否含有值。
文件比较
最后一类比较测试很有可能是shell编程中最为强大、也是用得最多的比较形式。它允许你测试Linux文件系统上文件和目录的状态。下表列出了这些比较。
比较 | 描述 |
---|---|
-d file | 检查 file 是否存在并是一个目录 |
-e file | 检查 file 是否存在 |
-f file | 检查 file 是否存在并是一个文件 |
-r file | 检查 file 是否存在并可读 |
-s file | 检查 file 是否存在并非空 |
-w file | 检查 file 是否存在并可写 |
-x file | 检查 file 是否存在并可执行 |
-O file | 检查 file 是否存在并属当前用户所有 |
-G file | 检查 file 是否存在并且默认组与当前用户相同 |
file1 -nt file2 | 检查 file1 是否比 file2 新 |
file1 -ot file2 | 检查 file1 是否比 file2 旧 |
检查目录
-d 测试会检查指定的目录是否存在于系统中。如果你打算将文件写入目录或是准备切换到某个目录中,先进行测试总是件好事情。
检查对象是否存在
-e 比较允许你的脚本代码在使用文件或目录前先检查它们是否存在。
检查文件
-e 比较可用于文件和目录。要确定指定对象为文件,必须用 -f 比较。
检查是否可读
在尝试从文件中读取数据之前,最好先测试一下文件是否可读。可以使用 -r 比较测试。
检查空文件
应该用 -s 比较来检查文件是否为空,尤其是在不想删除非空文件的时候。要留心的是,当-s 比较成功时,说明文件中有数据。
检查是否可写
-w 比较会判断你对文件是否有可写权限。
检查文件是否可以执行
-x 比较是判断特定文件是否有执行权限的一个简单方法。虽然可能大多数命令用不到它,但如果你要在shell脚本中运行大量脚本,它就能发挥作用。
检查所属关系
-O 比较可以测试出你是否是文件的属主。
检查默认属组关系
-G 比较会检查文件的默认组,如果它匹配了用户的默认组,则测试成功。由于 -G 比较只会
检查默认组而非用户所属的所有组。
检查文件日期
最后一组方法用来对两个文件的创建日期进行比较。这在编写软件安装脚本时非常有用。有时候,你不会愿意安装一个比系统上已有文件还要旧的文件。
-nt 比较会判定一个文件是否比另一个文件新。如果文件较新,那意味着它的文件创建日期更近。 -ot 比较会判定一个文件是否比另一个文件旧。如果文件较旧,意味着它的创建日期更早。
复合条件测试
if-then 语句允许你使用布尔逻辑来组合测试。有两种布尔运算符可用:
- [ condition1 ] && [ condition2 ]
- [ condition1 ] || [ condition2 ]
第一种布尔运算使用 AND 布尔运算符来组合两个条件。要让 then 部分的命令执行,两个条件都必须满足。
!布尔逻辑是一种能够将可能的返回值简化为 TRUE 或 FALSE 的方法。
第二种布尔运算使用 OR 布尔运算符来组合两个条件。如果任意条件为 TRUE , then 部分的命
令就会执行。
if-then 的高级特性
bash shell提供了两项可在 if-then 语句中使用的高级特性:
- 用于数学表达式的双括号
- 用于高级字符串处理功能的双方括号
使用双括号 13
双括号命令允许你在比较过程中使用高级数学表达式。 test 命令只能在比较中使用简单的算术操作。双括号命令提供了更多的数学符号,这些符号对于用过其他编程语言的程序员而言并不陌生。双括号命令的格式如下:
(( expression ))
expression 可以是任意的数学赋值或比较表达式。除了 test 命令使用的标准数学运算符,下表列出了双括号命令中会用到的其他运算符。
符号 | 描述 |
---|---|
val++ | 后增 |
val– | 后减 |
++val | 先增 |
–val | 先减 |
! | 逻辑求反 |
~ | 位求反 |
** | 幂运算 |
<< | 左位移 |
>> | 右位移 |
& | 位布尔和 |
| | 位布尔或 |
&& | 逻辑和 |
|| | 逻辑或 |
可以在 if 语句中用双括号命令,也可以在脚本中的普通命令里使用来赋值。
注意,不需要将双括号中表达式里的大于号转义。这是双括号命令提供的另一个高级特性。
使用双方括号
双方括号命令提供了针对字符串比较的高级特性。双方括号命令的格式如下:
[[ expression ]]
双方括号里的 expression 使用了 test 命令中采用的标准字符串比较。但它提供了 test 命令未提供的另一个特性——模式匹配(pattern matching)。
在模式匹配中,可以定义一个正则表达式来匹配字符串值。
case 命令
有了 case 命令,就不需要再写出所有的 elif 语句来不停地检查同一个变量的值了。 case 命令会采用列表格式来检查单个变量的多个值。
case variable in
pattern1 | pattern2) commands1;;
pattern3) commands2;;
*) default commands;;
esac
case 命令会将指定的变量与不同模式进行比较。如果变量和模式是匹配的,那么shell会执行为该模式指定的命令。可以通过竖线操作符在一行中分隔出多个模式模式。星号会捕获所有与已知模式不匹配的值。case 命令提供了一个更清晰的方法来为变量每个可能的值指定不同的选项。
可能是心情好,今晚突然想写博客,就更新了这篇。我和我女友和好了,真的很开心,希望不会再分开了吧