Merge pull request '完成条件判断' (#1) from cxykevin/learn-linux-basic:main into main
Build and Publish / Run (push) Successful in 7m20s Details

Reviewed-on: #1
This commit is contained in:
cxykevin 2024-09-19 22:25:02 +08:00
commit 6dbdf4d140
2 changed files with 280 additions and 1 deletions

View File

@ -25,7 +25,7 @@
- [Job]()
- [Vim编辑器](./shell_and_shell_script/vim_editor.md)
- [Shell Script基本语法](./shell_and_shell_script/shell_script_basic.md)
- [条件判断语句]()
- [条件判断语句](./shell_and_shell_script/conditional_judgment.md)
- [循环]()
- [函数]()
- [at与corntab]()

View File

@ -0,0 +1,279 @@
# 条件判断语句
在前几章,我们学习了 Shell Script 的基本内容与编辑。那么,如果想要在根据不同情况做一些事情,例如在不同发行版上干不同的事情,或者根据不同参数执行不同的命令,那么就需要用到条件判断语句了。
> 如果你学习过其它任何的编程语言那么条件判断语句对你来说应该不会陌生。但是Shell Script 的条件判断语句的语法十分特别,但是功能都是相似的。
## 条件判断
### 方括号 `[]`
在 Shell Script 中,最常用的条件判断语句就是方括号语句了。方括号语句的语法如下:
```bash
[ 运算符 变量 ] # 一个个变量的运算
[ 变量1 运算符 变量2 ] # 两个变量的运算
```
方括号语句的语法很简单,就是方括号内写上你的条件判断语句,然后在外面写上 `[]` 即可。
> 方括号其实和 `test` 命令的功能一模一样,但是方括号可以使代码可读性更高。
注意:方括号语句的语法要求方括号内必须有空格,否则会报错。
> 方括号判断的结果就是命令的返回值,也就是 `$?`,如果返回值为 0则表示条件判断为真否则表示条件判断为假可以使用 `echo $?` 查看。
方括号语句内可以写各种运算符:
### 数值比较
| 运算符 | 含义 | 符号 | 结果为真例子 | 结果为假例子 |
| :----: | :--------: | :-: | :------------- | :------------- |
| `-eq` | 等于 | = | `[ 1 -eq 1 ]` | `[ 1 -eq 2 ]` |
| `-ne` | 不等于 | != | `[ 1 -ne 2 ]` | `[ 1 -ne 1 ]` |
| `-gt` | 大于 | > |`[ 2 -gt 1 ]` | `[ 1 -gt 1 ]` |
| `-lt` | 小于 | < |`[ 1 -lt 2 ]` | `[ 2 -lt 1 ]` |
| `-ge` | 大于等于 | >= |`[ 1 -ge 1 ]` | `[ 1 -ge 2 ]` |
| `-le` | 小于等于 | <= |`[ 2 -le 2 ]` | `[ 2 -le 1 ]` |
> 这里的等于和不等于只能用数字,不能使用字符串
### 字符串比较
| 运算符 | 含义 | 结果为真例子 | 结果为假例子 |
| :----: | :--------: | :------------- | :------------- |
| `==` | 等于 | `[ a == a ]` | `[ a == b ]` |
| `!=` | 不等于 | `[ a != b ]` | `[ 1 != 1 ]` |
| `-n` | 字符串长度 > 0 | `[ -n abc ]` | `[ -n '' ]` |
| `-z` | 字符串长度 = 0 |`[ -z "" ]` | `[ -z abc ]` |
> 这里等于后面可以是字符串,也可以是数字,因为数字也会被变成字符串。但是比较数字还是建议使用明确的 `-eq`
在字符串比较中,如果传入了一个带空格的字符串,例如 `"hello world"`,那么方括号语句会认为这是一个错误,因为方括号语句会认为这是前后两个字符串。所以,引用变量最好使用双引号包裹,例如 `[ "$var" == "hello world" ]`
### 文件判断
> 下文假设当前目录下有一个 `file1` 文件和一个 `dir1` 目录
| 运算符 | 含义 | 结果为真例子 | 结果为假例子 |
| :----: | :--------: | :------------- | :------------- |
| `-e` | 存在文件或目录 | `[ -e file1 ]` | `[ -e file2 ]` |
| `-f` | 存在指定的文件 | `[ -f file1 ]` | `[ -f dir1 ]` |
| `-d` | 存在指定的目录 | `[ -d dir1 ]` | `[ -d file1 ]` |
### 逻辑运算符
> 下面大括号内的内容仅方便理解,不是 Bash 命令。
| 运算符 | 含义 | 结果为真例子 | 结果为假例子 |
| :----: | :--------: | :------------- | :------------- |
| `-a` | 与 | `[ 1 -eq 1 -a 2 -eq 2 ]` { ***(1==1) and (2==2)*** } | `[ 1 -eq 1 -a 2 -eq 1 ]` { ***(1==1) and (2==1)*** } |
| `-o` | 与 | `[ 1 -eq 1 -o 2 -eq 1 ]` { ***(1==1) or (2==1)*** } | `[ 1 -eq 2 -o 2 -eq 1 ]` { ***(1==2) or (2==1)*** } |
| `!` | 非 | `[ ! 1 -eq 2 ]` | `[ ! 1 -eq 1 ]` |
> 就像与运算的示例一样,你可以在一个方括号内写多个表达式。你只需要记住,`-a` 和 `-o` 会被最后计算,而且 `-a` 的优先级比 `-o` 高,也就是会先算 `-a`
### 双方括号 `[[]]`
双方括号被大多数 Shell 支持(例如在部分系统默认的 `sh` 中就不支持),用起来比方括号更加方便。但是,在简单判断时,出于兼容性考虑更推荐单方括号。
双方括号的语法和单方括号没有什么区别:
```bash
[[ 运算符 变量 ]] # 一个个变量的运算
[[ 变量1 运算符 变量2 ]] # 两个变量的运算
```
双方括号内可以直接使用上面的所有运算符,也可以使用 `>` 等数值比较运算符(注意:大于等于不支持)和 `&&`(与)、`||`(或)等逻辑运算符。
另外,在双方括号中,我们可以使用小括号来指定运算的顺序,就像在数学中一样(在 Bash 中不允许嵌套)。小括号和中括号一样需要加空格。例如:
```bash
[[ ( 2 > 1 ) || ( 1 > 2 ) && ( 1 > 1 ) ]]
# 读者可以尝试一下在不使用 Bash 的情况下猜猜运行结果
```
在双方括号中不需要和单方括号一样,引用字符串变量使用 `""` 包裹。例如之前的例子:
```bash
[ "$var" == "hello world" ]
# 等价于
[[ $var == "hello world" ]]
```
## `if` 语句
`if` 语句的语法十分简单:
```bash
if 条件语句; then
# 你的任何代码
fi
```
例如:
```bash
# 输入密码到 var 变量中
read -s -p "请输入你的密码:" var
# 判断密码是否是 "password"
if [ $var == "password" ]; then
echo "密码正确"
fi
```
> 在条件语句中,可以写 `true``false`,可以直接表示真或者假。也可以写任何命令行,只要程序的返回值为 0 就表示真,非 0 就表示假。这几种参数都不需要在方括号中。
还可以有 `elif``else` 语句:
```bash
if 条件语句1; then
# 你的任何代码
elif 条件语句2; then
# 当上面的条件语句都为假,
# 并且当前条件语句为真时
# 执行这里的代码
# elif 可以有多个,不是必须的
else
# 当上面所有条件语句为假时
# 执行这里的代码
# else 也不是必须的
fi
```
例如:
```bash
# 输入用户名到 var 变量中
read -p "请输入你的用户名:" var
# 判断用户是否是 "user1"
if [ $var == "user1" ]; then
echo "User1 你好"
# 判断用户是否是 "user2"
elif [ $var == "user2" ]; then
echo "User2 你好"
# 判断用户是否是 "user3"
elif [ $var == "user3" ]; then
echo "User3 你好"
# 如果都不是
else
echo "找不到该用户"
fi
```
`if` 语句的“可玩性”非常高,你已经可以写出很多有趣的脚本了。我们下面还会学习循环和函数,这样你就可以写出更加复杂的脚本了。
## `case`
`case` 语句和 `if` 语句类似。但是,如果你有几十条内容,那么 `if` 就显得不太“优雅”并且难以维护了。
> 一般来说3 项以上的 `if` 就应该写成 `case` 形式了。`case` 比 `if` 更容易阅读和维护。
下面是 `case` 的语法: ~~(感觉很奇怪)~~
```bash
case 变量 in
值1)
# 当变量等于值1时
# 执行这里的代码
;;
值2)
# 当变量等于值2时
# 执行这里的代码
;;
*)
# 当变量等于其他值时
# 执行这里的代码
# 不是必须的
;;
esac
```
> 注意:每一行最后的双分号 `;;` 是必须的,表示结束当前分支。
>
> 如果你比较细心,会发现 `esac` 就是 `case` 倒过来写,可以用这个来记忆。前面的 `if` 也是一个道理。
例如上面判断用户名的代码就可以改写成:
```bash
read -p "请输入你的用户名:" var
case $var in
"user1")
echo "User1 你好"
;;
"user2")
echo "User2 你好"
;;
"user3")
echo "User3 你好"
;;
*)
echo "找不到该用户"
;;
esac
```
无论是 `if` 还是 `case`,还是后面要学习的循环语句,之间都是可以被随意嵌套的。例如:
```bash
read -p "请输入一个数字:" var
if [ $var -gt 5 ]; then
echo "数字大于 5"
if [ $var -gt 10 ]; then
echo "数字大于 10"
fi
else
echo "数字小于或等于 5"
fi
```
## `&&``||`
`&&``||` 是 Shell 中的逻辑运算符,用于连接多个条件。
- `&&`:表示“与”关系,只有当它两边的条件都为真时,整个表达式才为真。
- `||`:表示“或”关系,只要它两边的条件有一个为真,整个表达式就为真。
例如:
```bash
read -p "请输入你的用户名:" var
read -s -p "请输入你的密码:" var2
if [ $var == "user" ] && [ $var2 == "password" ]; then
echo "登录成功"
else
echo "登录失败"
fi
```
> 这两个符号遵循一种叫做“短路”的规则:
>
> `&&` 符号当前一条命令为假时,后面的命令就不会执行了。
>
> `||` 符号当前一条命令为真时,后面的命令同样不会执行。
>
> “短路”的“可玩性”其实很高,更多的用法就等待读者自行探索了。另外,这两个符号可以像分号一样连接两个命令(遵循“短路”的规则),例如 `echo 1&&echo 2`
## 课后作业
这节课的学习压力稍微大一些,但是用处比较大,对于后面的学习有一定帮助。为了更好掌握这个知识点,您可以尝试完成以下作业:
1. 编写一个脚本,判断用户输入的数字是否大于 10。
2. 经典问题:判断一个年份是不是闰年。
> 提示:可以使用 `[ $[ 数字 % 4 ] == 0 ]` 来判断一个数是否能被 4 整除。
闰年的定义是:能被 4 整除但不能被 100 整除,或者能被 400 整除的年份。
> 读者可以尝试使用 `if` 嵌套,也可以使用 `&&` `||` 来实现。
3. 模拟一个软件的安装。复制当前目录下的 `some_software``/opt/some_software`,但是当 `/opt/some_software` 存在时,请先删除这个目录。
4. 为上一题的软件编写一个卸载脚本,如果找不到这个目录就显示 `软件未安装`,否则提示用户确认后然删除这个目录。
---
> study-area-cn