
Shell小笔记(二)
本文以 Bash 为准。代码中的方括号、分号和引号都使用半角字符,复制时别让中文标点来偷袭。
条件测试语句
基本语法
(1)test <条件>
(2)[ <条件> ] 需要注意方括号与条件之间要有空格
结果:条件成立时,测试命令的退出状态为 0;不成立时为 1,测试写法错误时还可能返回其他非零状态。
仅当条件是单个字符串时,才按“非空为真、空为假”判断。这里的 0 指退出状态;在 (( 算术表达式 )) 中,则是表达式数值非零为真、零为假,别混在一起。
1 | test homo; echo $? #输出0,因为homo是非空字符串 |
文件测试
配合操作符,可以实现文件或者目录类型的检测。
例如,检测当前路径下的 homo 是不是目录?
1 | touch homo |
以下是文件测试操作符与相应说明的对应关系
| 操作符 | 说明 |
|---|---|
| -d | 测试是否为目录(Directory) |
| -e | 测试目录或文件是否存在(Exist) |
| -f | 测试是否为普通文件(File) |
| -r | 测试当前用户是否可读(read) |
| -w | 测试当前用户是否可写(write) |
| -x | 测试当前用户是否可执行(execute) |
整数测试
整数测试通常用于数值之间的比较,在一些逻辑关系的判断中有应用。
例如判断 1+1+5+4 与 1+9+1 是否相等,可以这么写
1 | [ "$((1+1+5+4))" -eq "$((1+9+1))" ]; echo $? #输出0,都是11 |
以下是关系测试操作符与相应说明的对应关系
| 操作符 | 关系运算符 | 说明 |
|---|---|---|
| -eq | == | 等于(Equal) |
| -ne | != | 不等于(Not Equal) |
| -gt | > | 大于(Greater Than) |
| -lt | < | 小于(Lesser Than) |
| -le | <= | 小于或等于(Lesser or Equal) |
| -ge | >= | 大于或等于(Greater or Equal) |
字符串测试
字符串测试操作符的作用包括比较字符串是否相同、测试字符串的长度是否为0。
格式为:[ "$str1" = "$str2" ];测试长度时写成 [ -z "$str" ] 或 [ -n "$str" ]。给变量加双引号,空字符串和带空格的内容才不会拆坏测试语句。
以下是字符串测试操作符与相应说明的对应关系
| 操作符 | 含义 |
|---|---|
| -z | 判断字符串长度是否为 0 |
| -n | 判断字符串长度是否为 非0 |
| != | 判断两边字符串是否 不相等 |
| = | 判断两边字符串是否 相等 |
逻辑运算符
在Shell条件测试中,使用逻辑运算符实现复杂的条件测试,逻辑运算符用于组合条件,! 则对条件取反。
格式为:[ 条件1 ] && [ 条件2 ] 或 [ 条件1 ] || [ 条件2 ]。
注意:旧写法 -a 和 -o 放在 [ ] 里面用,但复杂条件容易产生歧义,建议拆成多个测试后用 &&、|| 连接。Bash 的 [[ 条件1 && 条件2 ]] 也支持在内部使用 &&、||。
以下是逻辑运算操作符与相应说明的对应关系
| 操作符 | 含义 |
|---|---|
| -a 或 && | 与 |
| -o 或 || | 或 |
| ! | 否 |
下面的流程控制语法使用“条件表达式”“代码块”等文字占位;实际使用时需替换为具体条件或命令。循环示意中的 name 是循环变量。
if条件
很常见的判断语句,不过要注意Shell中的流程控制不能为空
即如果 else 分支没有语句执行,就不需要写;如果要临时占位,可以写 :(空命令)。
if单分支
1 | if [ 条件表达式 ];then |
if双分支
1 | if [ 条件表达式 ] |
if多分支
1 | if [ 条件表达式1 ];then |
case条件
程序会获取case语句中的变量值
如果满足条件表达式1,则执行代码块 1
如果满足条件表达式2,则执行代码块2
如果满足条件表达式3,则执行代码块3
执行到双分号
;;,则停止如果前面的模式都不匹配,则执行
*)后面的代码块;它应放在最后作为默认分支只要满足一个条件表达式就会跳出
case语句主体,执行esac字符后面的命令
1 | case 变量值 in |
case 中使用的是 Shell 通配模式,不是正则表达式,也不是数值条件测试。匹配符如下表所示
| 条件表达式 | 说明 |
|---|---|
| * | 任意长度的字符串(包括空字符串) |
| ? | 任意单个字符 |
| [abc] | a、b或c其中之一 |
| [a-n] | 从a到n的任一字符 |
| | | 多重选择 |
for循环
语法
for 循环依次取列表中的每一项,赋给循环变量,然后执行一次循环体;列表为空时不执行。
in 的取值列表支持替换、字符串和文件名;不用取值列表将使用命令行的位置参数
通常写法
1 | for name in 值1 值2 |
一行写法
1 | for name in 值1 值2; do 命令; done |
💡提醒:写成一行(在终端直接执行)时,需要记得加 ; 符号。
例子
列表不长时,直接交给 for 就行:
1 | for num in 114514 1919 810; do |
while循环
用于不断执行一系列命令,也用于从输入文件中读取数据
语法
常规写法
1 | while [ 条件表达式 ] |
无限循环
1 | while : #也可写成while true |
例子
1 | !/bin/bash |
批量创建用户
脚本将读取用户清单文件(格式:用户名 密码,用空白分隔),据此创建用户并配置密码。for 适合遍历已经准备好的列表;逐行处理文件时,使用下面的 while read 更合适,可以保留空行,也避免命令替换后发生额外的通配符展开。
下面的脚本面向 Linux,需要 root 权限以及
useradd、chpasswd命令;会实际创建用户。清单中每行两个字段,用户名和密码不含空白或冒号,清单里保存的是明文密码,应限制文件访问权限。
1 |
|
原来的 echo "密码 | passwd ..." 只会打印文本,不会执行管道。这里使用 chpasswd 接收 用户名:密码;某些 Linux 发行版的 passwd --stdin 也能读取密码,但不是通用选项。
until循环
与 while 循环相反,until 在条件为假时执行循环体,在条件为真时停止。它同样先检查条件,不保证至少执行一次。
语法
如果条件表达式的返回值为 false,则继续执行循环体内的语句,否则跳出循环。
1 | until [ 条件表达式 ] |
例子
1 | !/bin/bash |
跳出循环
在循环过程中,有时候需要在未达到循环结束条件时强制跳出循环。break 默认退出当前一层循环;continue 跳过本轮剩余语句,开始下一轮。嵌套循环中可以使用 break 2 退出两层,或 continue 2 继续外层循环的下一轮。








