1. 条件测试:test 和 [
命令 test 或 [ 可以测试一个条件是否成立,如果测试结果为真,则该命令的退出码为 0,如果测 试结果为假,则命令的退出码为 1 (与C语言的逻辑表示正好相反)。
当我们在进行比较时,不能使用 C 语言风格的 ==、!= ,而要使用 -eq(等于)、-ne(不等于)、-gt(大于)、-ge(大于等于)、-lt(小于)、-le(小于等于)。
$? 表示上一条命令的退出码,echo $? 查看命令结果成功与否。0 真,非 0 假。
测试两个数的大小关系:
命令 test 或 [ 的参数形式是相同的,只不过 test 命令不需要 ] 参数。
常见的测试命令如下:
read命令的作用是等待用户输入一行字符串,将该字符串存到一个 Shell 变量中。
测试条件之间还可以做与、或、非逻辑运算:
2. if 语句
和 C 语言类似,在 Shell 中用 if、then、elif、else、fi 这几条命令实现分支控制。这种流程控制语句本质上也是由若干条 Shell 命令组成的。
其实是三条命令,if [ -f~/.bashrc ] 是第一条,then . ~/.bashrc 是第二条,fi 是第三条。如果两条命令写在同一行则需要用 ; 号隔开,一行只写一条命令就不需要写 ; 号,另外,then 后面有换行,但这条命令没写完,Shell会自动续行,把下一行接在 then 后面当作一条命令处理。
和 [ 命令一样,要注意命令和各参数之间必须用空格隔开。
if 命令的参数组成一条子命令,如果该子命令的退出码为 0 (表示真),则执行 then 后面的子命令,如果退出码非 0 (表示假),则执行 elif、else 或者 fi 后面的子命令。if 后面的子命令通常是测试命令,但也可以是其它命 令。
Shell 脚本没有 {} 括号,所以用 fi 表示 if 语句块的结束。
&& 相当于 “if...then...”,而 || 相当于 “if not...then...”。&& 和 || 用于连接两个命令,-a 和 -o 仅用于测试表达式中连接两个测试条件。
在进行条件判断时, [ 和 [[ 最大的区别是,[[ 支持通配符和正则表达式。
3. case 语句
case 命令可类比 C 语言的 switch/case 语句,esac 表示 case 语句块的结束。C 语言的 case 只能匹配整型或字符型常量表达式,而 Shell 脚本的 case 可以匹配字符串和通配符,每个匹配分支可以有若干条命令,末尾必须以 ;; 结束,执行时找到第一个匹配的分支并执行相应的命令,然后直接跳到 esac 之后,不需要像 C 语言一样用 break 跳出。
$1 是一个特殊变量,在执行脚本时自动取值为第一个命令行参数,也就是 start,所以进入 start ) 分支执行相关的命令。同理,命令行参数指定为 stop、reload 或restart 可以进入其它分支执行停止服务、重新加载配置文件或重新启动服务的相关命令。
4. 循环语句
1)for 循环
打印 0-99
遍历1-100
2)while 循环
(1)while / do / done
遍历 0-100
一行写多条命令,语句用 ; 隔开,也得到了相同的结果。
(2)until
Shell 还有 until 循环,类似 C 语言的 do...while 循环。
遍历 0-100
3): 空命令
: 是一个特殊的命令,称为空命令,该命令不做任何事,但退出码总是真。
循环体内不能什么都不写(不能为空),条件判断中也不能什么都不写,如果我们不想写内容,就可以加上空命令 :。
(1)死循环
(2)条件是否成立
5. 位置参数和特殊变量
有很多特殊变量是被 Shell 自动赋值的,常用的位置参数和特殊变量有:
$0:相当于 C 语言 main 函数的 argv[0],即命令或可执行程序。
$1、$2...、$n:这些称为位置参数(Positional Parameter),相当于 C 语言 main 函数的 argv[1]、argv[2]...、argv[n],表示命令行参数。
$#:相当于 C 语言 main 函数的 argc - 1,也就是参数的个数。这里的 # 后面不表示注释。
$@:表示参数列表 "$1" "$2" ...,例如可以用在 for 循环中的 in 后面。
$?:上一条命令的退出码。
$$:当前 Shell 的进程号。
位置参数可以用 shift 命令左移。比如 shift 3 表示原来的 $4 现在变成 $1,原来的 $5 现在变成 $2 等等,原来的 $1、$2、$3 丢弃,$0 不移动。不带参数的 shift 命令相当于shift 1。
6. 函数
和 C 语言类似,Shell 中也有函数的概念,但是函数定义中没有返回值也没有参数列表。例如:注意函数体的左花括号 { 和后面的命令之间必须有空格或换行,如果将最后一条命令和右花括号 } 写在同一行,命令末尾必须有 ; 号。
在定义 foo() 函数时并不执行函数体中的命令,就像定义变量一样,只是给 foo 这个名字一个定义, 到后面调用 foo 函数的时候(注意 Shell 中的函数调用不写括号)才执行函数体中的命令。
Shell 脚本中的函数必须先定义后调用,一般把函数定义都写在脚本的前面,把函数调用和其它命令写在脚本的最后(类似 C 语言中的 main 函数,这才是整个脚本实际开始执行命令的地方),函数体内不能为空。
Shell 函数没有参数列表并不表示不能传参数,事实上,函数就像是迷你脚本或程序,调用函数时可以传任意个参数,在函数内同样是用 $0、$1、$2 等变量来提取参数,函数中的位置参数相当于函数的局部变量,改变这些变量并不会影响函数外面的 $0、$1、$2 等变量。函数中可以用 return 命令返回,如果 return 后面跟一个数字则表示函数的退出码。
Shell 函数定义的变量默认在当前 bash 内全局有效,若只想在函数体内有效,就在定义时加上 local。
Shell 脚本是支持递归的。
举例:编写函数求最值。
7. Shell 脚本的调试方法
Shell 提供了一些用于调试脚本的选项,如下所示:
-n:读一遍脚本中的命令但不执行,用于检查脚本中的语法错误。
-v、-x:提供跟踪执行信息,将执行的每一条命令和结果依次打印出来。
使用这些选项有三种方法:
1)在命令行提供参数:$ sh -x ./script.sh
2)在脚本开头提供参数#! /bin/sh -x
3)在脚本中用 set 命令启用或禁用参数
set -x 和 set +x 分别表示启用和禁用 -x 参数,这样可以只对脚本中的某一段进行跟踪调试。
8. 数组
bash 支持一维数组(不支持多维数组),并且没有限定数组的大小。类似于 C 语言,数组元素的下标由 0 开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于 0。
定义数组:在 Shell 中,用括号 () 来表示数组,数组元素用“空格”符号分割开。定义数组的一般形式为: array_name=(value1 ... valuen),例如:arr=(3.14 'c' "hello" 123)
还可以单独定义数组的各个分量,可以不使用连续的下标,而且下标的范围没有限制。
读取数组:读取数组元素值的一般格式是:${array_name[index]},例如:echo ${arr[2]}
使用 @ 或 * 可以获取数组中的所有元素,echo ${arr[@]} 或 echo ${arr[*]}
获取元素个数:echo ${#arr[*]}
遍历数组元素: