一、if语法
在 Shell 脚本中,if 语句用于根据命令的退出状态来条件性地执行代码块。其基本结构和常用变体如下:
1. 标准 POSIX if 语法 ([ ] 或 test 命令)
这是所有 POSIX 兼容 Shell(包括 Bash, Zsh, Dash, Sh)都支持的语法。
1.1 基本 if
语法:
1 | if condition; then commands; fi |
关键参数:
if: 开始一个条件判断。condition: 任何命令。其退出状态码决定if语句的真假(0表示真/成功,非0表示假/失败)。最常用的是test命令,或其别名[。then: 如果condition为真,则执行then后面的commands。fi: 结束if语句块。;: 当then和condition在同一行时,需要用;分隔。
One-liner 示例:
检查文件是否存在且是普通文件:
1 | if [ -f "myfile.txt" ]; then echo "文件存在"; fi |
解释: [ -f "myfile.txt" ] 检查 myfile.txt 是否存在且为普通文件。-f 是 test 命令的操作符。
1.2 if-else
语法:
1 | if condition; then commands1; else commands2; fi |
关键参数:
else: 如果condition为假,则执行else后面的commands2。
One-liner 示例:
判断目录是否存在:
1 | if [ -d "/tmp" ]; then echo "/tmp 是目录"; else echo "/tmp 不是目录"; fi |
1.3 if-elif-else (多重条件)
语法:
1 | if condition1; then commands1; elif condition2; then commands2; else commands3; fi |
关键参数:
elif: “else if” 的缩写。如果前一个if或elif的条件为假,则尝试判断当前elif的条件。
One-liner 示例:
判断变量值:
1 | MYVAR="foo"; if [ "$MYVAR" = "bar" ]; then echo "是 bar"; elif [ "$MYVAR" = "foo" ]; then echo "是 foo"; else echo "都不是"; fi |
1.4 test (即 [ ]) 命令的常用操作符
test 命令或其简写 [ 用于评估条件。
文件测试:
-f FILE: FILE 存在且是普通文件。-d FILE: FILE 存在且是目录。-e FILE: FILE 存在 (GNU 和 BSD Shell 都支持,但 POSIX 未强制要求)。-s FILE: FILE 存在且大小不为零。-r FILE,-w FILE,-x FILE: FILE 存在且可读/写/执行。
字符串测试:
STRING1 = STRING2: 字符串相等。STRING1 != STRING2: 字符串不相等。-z STRING: 字符串长度为零 (空字符串)。-n STRING: 字符串长度不为零 (非空字符串)。
整数测试:
INT1 -eq INT2: 相等。INT1 -ne INT2: 不相等。INT1 -gt INT2: 大于。INT1 -lt INT2: 小于。INT1 -ge INT2: 大于等于。INT1 -le INT2: 小于等于。
One-liner 示例 (组合条件):
通过命令链实现逻辑 AND:
1 | if [ -f "log.txt" ] && [ -s "log.txt" ]; then echo "log.txt 是非空文件"; fi |
解释: && 是 Shell 的逻辑 AND 操作符,只有 && 左边的命令成功 (退出状态为 0) 时,右边的命令才会执行。整个 if 的 condition 就是由 && 连接的两个 test 命令。
2. Zsh/Bash 扩展 if 语法 ([[ ]])
[[ ... ]] 是 Bash 和 Zsh (以及某些其他非 POSIX Shell) 提供的更强大的条件表达式语法。它不是 POSIX 标准,但在 Bash/Zsh 脚本中非常常用。
优点:
- 无需严格引用: 在
[[ ]]内部,通常不需要对变量进行双引号引用 (如[[ $VAR = value ]]而非[ "$VAR" = "value" ]),Shell 会正确处理空格和通配符。 - 内置逻辑运算符: 支持
&&(AND),||(OR),!(NOT) 作为运算符,直接在[[ ]]内部组合条件,比[ ]的-a/-o更直观且没有优先级问题。 - 正则表达式匹配: 支持
=~操作符进行正则表达式匹配。 - 模式匹配:
==或=支持通配符匹配 (如[[ $VAR == *.txt ]])。 - 算术比较: 可以直接使用
>、<、>=、<=进行整数比较,无需-gt等。
One-liner 示例 (内置逻辑 AND/OR):
判断操作系统类型:
1 | MY_OS="macOS"; if [[ "$MY_OS" == "macOS" || "$MY_OS" == "Linux" ]]; then echo "是类 Unix 系统"; fi |
解释: || 在 [[ ]] 内部用作逻辑 OR。
One-liner 示例 (正则表达式匹配):
检查主机名是否符合特定模式:
1 | HOSTNAME="web-server-01"; if [[ "$HOSTNAME" =~ ^[a-z]+-server-[0-9]{2}$ ]]; then echo "主机名符合规范"; fi |
解释: =~ 是正则表达式匹配操作符。^[a-z]+-server-[0-9]{2}$ 是一个正则表达式,匹配以字母开头,后跟 -server- 和两位数字的字符串。
总结:
- POSIX 兼容性优先: 使用
[ ](test)。它在所有符合 POSIX 标准的 Shell 中都能工作,确保脚本的最大可移植性。 - Bash/Zsh 脚本:
[[ ]]提供了更强大的功能和更简洁的语法,推荐在确定脚本只运行在 Bash 或 Zsh 环境下时使用。
二、shell字体颜色
基本用法 (One-liner)
使用 echo -e 命令解析转义字符:
1 | echo -e "\033[31m这是红色文本\033[0m" |
常用颜色及样式代码
这些代码放在 \033[ 和 m 之间,多个代码可用分号 ; 分隔。
| 代码 | 描述 | 示例 |
|---|---|---|
0 |
重置 | 恢复默认颜色和样式 |
1 |
加粗 | \033[1m粗体文本\033[0m |
4 |
下划线 | \033[4m下划线文本\033[0m |
30 |
黑色前景 | \033[30m黑色文本\033[0m |
31 |
红色前景 | \033[31m红色文本\033[0m |
32 |
绿色前景 | \033[32m绿色文本\033[0m |
33 |
黄色前景 | \033[33m黄色文本\033[0m |
34 |
蓝色前景 | \033[34m蓝色文本\033[0m |
35 |
品红色前景 | \033[35m品红色文本\033[0m |
36 |
青色前景 | \033[36m青色文本\033[0m |
37 |
白色前景 | \033[37m白色文本\033[0m |
40 |
黑色背景 | \033[40m黑色背景\033[0m |
41 |
红色背景 | \033[41m红色背景\033[0m |
42 |
绿色背景 | \033[42m绿色背景\033[0m |
43 |
黄色背景 | \033[43m黄色背景\033[0m |
44 |
蓝色背景 | \033[44m蓝色背景\033[0m |
45 |
品红色背景 | \033[45m品红色背景\033[0m |
46 |
青色背景 | \033[46m青色背景\033[0m |
47 |
白色背景 | \033[47m白色背景\033[0m |
关键参数解释
echo -e:echo: 用于在终端输出文本。-e: (POSIX 兼容,macOS/BSD 和 GNUecho都支持) 启用对反斜杠转义序列的解释。这是关键,它让\033被识别为转义字符。
\033或\e:- 代表 ASCII 转义字符 (ESC, 十进制 27)。在 shell 中,
\033或\e(在某些 shell 中如 Bash/Zsh) 都可表示。
- 代表 ASCII 转义字符 (ESC, 十进制 27)。在 shell 中,
[:- 转义序列的开始。
...:- 一个或多个 SGR (Select Graphic Rendition) 参数。它们决定了文本的颜色、亮度等样式。多个参数用分号
;分隔。
- 一个或多个 SGR (Select Graphic Rendition) 参数。它们决定了文本的颜色、亮度等样式。多个参数用分号
m:- 转义序列的结束。
示例 (组合样式)
1 | echo -e "\033[1;33;44m这是一个粗体、黄色文本、蓝色背景的组合\033[0m" |
注意事项
\033[0m的重要性: 每次改变颜色或样式后,务必在文本结束后使用\033[0m将样式重置回默认值,否则后续的文本也会保持相同的颜色。printf替代echo -e: 如果echo -e在某些极端情况下不工作(极少见),printf是一个更 POSIX 兼容且功能更强大的替代品:1
printf "\033[32m这是绿色文本\033[0m\n"
\n用于换行,因为printf默认不换行。
三、定义新变量
在 Zsh/Bash 等 Shell 环境中,你可以通过将文本和变量引用置于双引号 " 中来定义一个新变量。
命令
1 | NEW_VAR="前缀文本 ${EXISTING_VAR} 后缀文本" |
示例
1 | # 假设有一个已存在的变量 |
关键参数和概念解释
NEW_VAR="... ": 这是 Shell 中定义或赋值变量的标准语法。- 双引号
":- 作用:允许内部的变量进行扩展(替换为它们的值),同时保留其中的空格、制表符等空白字符的字面含义。
- 重要性:如果省略双引号,Shell 会对
EXISTING_VAR的值进行词法分析(word splitting)和文件路径扩展(pathname expansion),这可能导致意料之外的行为,尤其当变量值包含空格或特殊字符时。
${EXISTING_VAR}(或$EXISTING_VAR):- 作用:变量扩展(Variable Expansion),Shell 会将其替换为
EXISTING_VAR变量的当前值。 - 最佳实践:推荐使用
${VARIABLE}语法而非简单的$VARIABLE。虽然在大多数情况下两者等效,但花括号可以明确变量名的边界,避免歧义,例如当变量后面紧跟其他字符时($VAR_suffix可能被解析为变量VAR_suffix而非VAR后跟_suffix)。
- 作用:变量扩展(Variable Expansion),Shell 会将其替换为
兼容性
这种变量定义和引用方式是所有遵循 POSIX 标准的 Shell(如 sh, bash, zsh)都支持的,因此在 macOS (BSD) 和 GNU/Linux 环境下均可通用。