材料与逻辑

从原子到结构,从数据到洞察

shell语法备忘

一、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 语句块。
  • ;: 当 thencondition 在同一行时,需要用 ; 分隔。

One-liner 示例:
检查文件是否存在且是普通文件:

1
if [ -f "myfile.txt" ]; then echo "文件存在"; fi

解释: [ -f "myfile.txt" ] 检查 myfile.txt 是否存在且为普通文件。-ftest 命令的操作符。

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” 的缩写。如果前一个 ifelif 的条件为假,则尝试判断当前 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) 时,右边的命令才会执行。整个 ifcondition 就是由 && 连接的两个 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 和 GNU echo 都支持) 启用对反斜杠转义序列的解释。这是关键,它让 \033 被识别为转义字符。
  • \033\e:
    • 代表 ASCII 转义字符 (ESC, 十进制 27)。在 shell 中,\033\e (在某些 shell 中如 Bash/Zsh) 都可表示。
  • [:
    • 转义序列的开始。
  • ...:
    • 一个或多个 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
2
3
4
5
6
7
8
9
# 假设有一个已存在的变量
MY_NAME="系统专家"

# 定义一个新变量,结合文本和 MY_NAME 的值
GREETING_MESSAGE="你好,我是 ${MY_NAME},很高兴为你服务!"

# 打印新变量的值
echo "$GREETING_MESSAGE"
# 预期输出: 你好,我是 系统专家,很高兴为你服务!

关键参数和概念解释

  • 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)。

兼容性

这种变量定义和引用方式是所有遵循 POSIX 标准的 Shell(如 sh, bash, zsh)都支持的,因此在 macOS (BSD) 和 GNU/Linux 环境下均可通用。