Linux之Shell编程(二)
1. 命令扩展
1.1 逻辑运算符(控制命令执行流程)
基于命令的退出状态码(0 表示成功,非 0 表示失败)决定后续命令是否执行,用于构建条件执行逻辑。
1. &&(逻辑与)
- 核心含义:仅当左侧命令执行成功(退出码 = 0)时,才执行右侧命令;若左侧失败,直接跳过右侧。
- 工作原理:Shell 从左到右解析,左侧命令执行完毕后,立即检查退出码,仅在码值为 0 时触发右侧命令。
- 详细示例:
- 左侧失败场景:
false && echo "成功"
- 执行过程:
false
是内置命令,执行后退出码为 1(失败),Shell 直接跳过右侧echo
,最终无任何输出。
- 执行过程:
- 左侧成功场景:
true && echo "成功"
- 执行过程:
true
执行后退出码为 0(成功),Shell 继续执行右侧echo
,终端输出 “成功”。
- 执行过程:
- 左侧失败场景:
- 适用场景:需要 “前一步成功后才执行下一步” 的操作,如 “编译成功后才安装”:
make && make install
。
2. ||(逻辑或)
- 核心含义:仅当左侧命令执行失败(退出码≠0)时,才执行右侧命令;若左侧成功,直接跳过右侧。
- 工作原理:与
&&
相反,左侧命令退出码非 0 时,触发右侧命令;退出码为 0 时,终止后续执行。 - 详细示例:
- 左侧失败场景:
false || echo "左侧失败,执行此处"
- 执行过程:
false
退出码为 1(失败),Shell 执行右侧echo
,终端输出 “左侧失败,执行此处”。
- 执行过程:
- 左侧成功场景:
true || echo "不会执行"
- 执行过程:
true
退出码为 0(成功),Shell 跳过右侧echo
,无任何输出。
- 执行过程:
- 左侧失败场景:
- 适用场景:需要 “前一步失败时执行备用操作” 的场景,如 “连接数据库失败时输出提示”:
mysql -u root -p || echo "数据库连接失败"
。
3. 组合逻辑(&& 与 || 结合)
- 核心规则:
A && B || C
遵循从左到右结合原则,等价于(A && B) || C
,即先判断A && B
的结果,再决定是否执行C
。 - 工作原理:
- 先执行
A
,若A
失败,A && B
整体失败,直接执行C
; - 若
A
成功,执行B
,若B
失败,A && B
整体失败,执行C
; - 若
A
和B
都成功,A && B
整体成功,跳过C
。
- 先执行
- 详细示例:
false && echo yes || echo fallback
- 执行步骤:
- 执行
false
,退出码 1(失败),false && echo yes
整体失败; - 触发
||
后的echo fallback
,终端输出 “fallback”。
- 执行
- 执行步骤:
- 注意事项:不可与 “if-else” 完全等同,若
B
的退出码可能为非 0,可能导致逻辑偏差。例如true && false || echo ok
,因B
(false
)失败,最终会执行echo ok
,输出 “ok”。
1.2 echo 命令(输出内容管理)
用于将指定文本输出到指定的 “数据流”(标准输出或标准错误),是 Shell 中最基础的输出工具。
1. 基本功能(输出到标准输出 stdout)
- 核心含义:默认将文本写入标准输出(stdout),对应文件描述符 1,最终会显示在终端(除非被重定向)。
- 语法格式:
echo [选项] [文本内容]
,常用选项-e
可解析转义字符(如\n
换行、\t
制表符)。 - 详细示例:
- 普通输出:
echo "hello world"
- 执行结果:终端直接输出 “hello world”,内容通过 stdout 传递。
- 解析转义字符:
echo -e "apple\nbanana"
- 执行结果:终端分行输出 “apple” 和 “banana”,
\n
被解析为换行符。
- 执行结果:终端分行输出 “apple” 和 “banana”,
- 普通输出:
2. 进阶功能(输出到标准错误 stderr)
- 核心含义:通过 “重定向符号
>&2
”,将文本写入标准错误(stderr),对应文件描述符 2,用于区分 “正常输出” 和 “错误提示”。 - 工作原理:
>&2
表示 “将当前输出流的目标,指向文件描述符 2(stderr)的目标”,默认情况下,stderr 也会显示在终端,但可单独重定向(与 stdout 区分)。 - 详细示例:
echo "this is error" >&2
- 执行过程:文本 “this is error” 通过 stderr 传递,终端会显示该内容,但若后续对 stdout 重定向(如
> file.txt
),该错误文本不会写入文件(仅 stdout 内容会写入)。
- 执行过程:文本 “this is error” 通过 stderr 传递,终端会显示该内容,但若后续对 stdout 重定向(如
- 适用场景:脚本中区分 “正常日志” 和 “错误日志”,如
if [ ! -f "file.txt" ]; then echo "文件不存在" >&2; fi
,文件不存在时,错误提示通过 stderr 输出。
1.3 标准文件描述符(FD:数据流的 “身份标识”)
Shell 中用 “数字” 标识不同的数据流,共 3 个核心描述符,用于统一管理 “输入” 和 “输出”,是重定向和管道功能的基础。
1. 核心描述符定义
文件描述符(FD) | 对应数据流 | 功能说明 | 默认目标 |
---|---|---|---|
0 | 标准输入(stdin) | 接收外部输入(如键盘输入、文件内容) | 键盘 |
1 | 标准输出(stdout) | 输出正常执行结果(如命令的正确反馈) | 终端 |
2 | 标准错误(stderr) | 输出错误信息(如命令执行失败的提示) | 终端 |
2. 数据流区分示例
通过实际命令演示 stdout 和 stderr 的差异,明确两者的独立传递特性:
- stdout 示例:
echo "out"
- 执行结果:终端输出 “out”,内容通过 FD 1(stdout)传递,若执行
echo "out" > file.txt
,内容会写入 file.txt(仅 stdout 被重定向)。
- 执行结果:终端输出 “out”,内容通过 FD 1(stdout)传递,若执行
- stderr 示例:
echo "err" >&2
- 执行结果:终端输出 “err”,内容通过 FD 2(stderr)传递,若执行
echo "err" >&2 > file.txt
,内容不会写入 file.txt(仅 stdout 被重定向到文件,stderr 仍输出到终端)。
- 执行结果:终端输出 “err”,内容通过 FD 2(stderr)传递,若执行
- 错误命令的 stderr 输出:
ls /no/such/path
- 执行过程:
/no/such/path
是不存在的路径,ls
命令执行失败,错误信息 “ls: cannot access '/no/such/path': No such file or directory” 通过 stderr(FD 2)输出到终端,若执行ls /no/such/path > out.txt
,out.txt 为空(stdout 无内容),错误信息仍显示在终端(stderr 未被重定向)。
- 执行过程:
1.4 重定向(改变数据流的 “目标位置”)
通过特定符号,将原本输出到终端(或从键盘输入)的数据流,改向到文件或其他位置,分为 “标准输出重定向”“标准错误重定向”“合并重定向” 和 “丢弃输出” 四类场景。
1. 标准输出(stdout)重定向:>(覆盖)与 >>(追加)
针对 FD 1(stdout),改变其输出目标为文件,核心区别在于 “是否保留文件原有内容”。
(1)>(覆盖重定向)
- 核心含义:将 stdout 的内容写入文件,若文件已存在,覆盖原有内容;若文件不存在,创建新文件。
- 工作原理:执行命令时,Shell 先清空目标文件(若存在),再将命令的 stdout 内容写入文件,原文件内容会被完全替换。
- 详细示例:
- 首次写入:
echo "first" > file.txt
- 执行结果:创建 file.txt,写入 “first”,
cat file.txt
输出 “first”。
- 执行结果:创建 file.txt,写入 “first”,
- 覆盖写入:
echo "second" > file.txt
- 执行结果:file.txt 原有内容 “first” 被清空,写入 “second”,
cat file.txt
输出 “second”。
- 执行结果:file.txt 原有内容 “first” 被清空,写入 “second”,
- 首次写入:
- 注意事项:使用时需谨慎,避免误覆盖重要文件(如
echo "test" > /etc/passwd
会破坏系统用户配置文件)。
(2)>>(追加重定向)
- 核心含义:将 stdout 的内容追加到文件末尾,若文件已存在,保留原有内容,新内容添加在文件最后;若文件不存在,创建新文件。
- 工作原理:执行命令时,Shell 直接将命令的 stdout 内容写入文件末尾,不修改原有内容,仅在文件尾部追加新数据。
- 详细示例:
- 首次写入:
echo "first" > file.txt
- 执行结果:file.txt 写入 “first”,
cat file.txt
输出 “first”。
- 执行结果:file.txt 写入 “first”,
- 追加写入:
echo "second" >> file.txt
- 执行结果:file.txt 末尾添加 “second”,
cat file.txt
输出 “first” 和 “second”(分行显示)。
- 执行结果:file.txt 末尾添加 “second”,
- 首次写入:
- 适用场景:日志记录(如脚本运行日志),如
echo "$(date):脚本执行成功" >> script.log
,每次执行都在日志文件末尾追加新记录。
2. 标准错误(stderr)重定向:2>(覆盖)与 2>>(追加)
针对 FD 2(stderr),单独改变错误信息的输出目标,避免错误信息与正常输出混淆。
(1)2>(覆盖错误重定向)
- 核心含义:将 stderr 的错误信息写入文件,若文件已存在,覆盖原有内容;若文件不存在,创建新文件。
- 语法解析:“2” 代表 FD 2(stderr),“>” 代表重定向,组合后 “2>” 表示 “将 FD 2 的内容重定向到文件”。
- 详细示例:
ls /no/such/path 2> err.txt
- 执行过程:
ls
命令因路径不存在产生错误,错误信息通过 stderr 传递,Shell 将该信息写入 err.txt(覆盖原有内容),终端无任何输出(错误信息已被重定向到文件),cat err.txt
输出 “ls: cannot access '/no/such/path': No such file or directory”。
- 执行过程:
(2)2>>(追加错误重定向)
- 核心含义:将 stderr 的错误信息追加到文件末尾,保留文件原有内容,新错误信息添加在最后。
- 详细示例:
- 首次错误记录:
ls /no/such/path 2>> err.txt
- 执行结果:err.txt 写入第一条错误信息。
- 追加错误记录:
ls /another/no/path 2>> err.txt
- 执行结果:err.txt 末尾添加第二条错误信息,
cat err.txt
会显示两条不同的错误提示(分别对应两个不存在的路径)。
- 执行结果:err.txt 末尾添加第二条错误信息,
- 首次错误记录:
- 适用场景:收集命令或脚本的所有错误信息,如
./script.sh 2>> error.log
,脚本执行过程中所有错误都会追加到 error.log,便于后续排查问题。
3. 合并重定向(同时处理 stdout 和 stderr)
将 FD 1(stdout)和 FD 2(stderr)的内容,一起重定向到同一文件,适用于需要 “同时记录正常输出和错误信息” 的场景,主要有两种实现方式(兼容性不同)。
(1)POSIX 推荐写法(兼容所有 Shell):command > file.txt 2>&1
- 核心含义:先将 stdout(FD 1)重定向到 file.txt,再将 stderr(FD 2)的目标 “指向当前 stdout 的目标”(即 file.txt),最终两者的内容都写入 file.txt。
- 语法解析:
- “> file.txt”:第一步,将 FD 1 的输出目标改为 file.txt;
- “2>&1”:第二步,“&1” 表示 “FD 1 当前的目标”(此时已改为 file.txt),因此 FD 2 的输出目标也变为 file.txt。
- 详细示例:
bash -c 'echo out; echo err >&2' > both.txt 2>&1
- 执行过程:
bash -c '...'
:执行括号内的两条命令,第一条echo out
输出到 stdout(FD 1),第二条echo err >&2
输出到 stderr(FD 2);- “> both.txt”:将 FD 1 的内容(“out”)重定向到 both.txt;
- “2>&1”:将 FD 2 的内容(“err”)也重定向到 both.txt;
- 执行结果:
cat both.txt
输出 “out” 和 “err”(分行显示),终端无任何输出。
- 执行过程:
- 关键注意事项:顺序不可颠倒
若写成command 2>&1 > file.txt
,执行逻辑完全不同:- 第一步 “2>&1”:将 FD 2 的目标指向 “FD 1 的初始目标”(即终端);
- 第二步 “> file.txt”:将 FD 1 的目标改为 file.txt;
- 最终结果:stdout(FD 1)内容写入 file.txt,stderr(FD 2)内容输出到终端(未被重定向)。
- 示例验证:
bash -c 'echo out; echo err >&2' 2>&1 > both.txt
- 执行结果:终端输出 “err”(stderr 未被重定向),
cat both.txt
输出 “out”(仅 stdout 被写入文件)。
- 执行结果:终端输出 “err”(stderr 未被重定向),
(2)Bash 特殊简写(仅支持 Bash/ksh/zsh)
- ① &>(合并重定向到文件):
command &> file.txt
- 核心含义:等价于
command > file.txt 2>&1
,直接将 stdout 和 stderr 都写入 file.txt,语法更简洁。 - 详细示例:
bash -c 'echo out; echo err >&2' &> both.txt
- 执行结果:
cat both.txt
输出 “out” 和 “err”,与 POSIX 写法效果一致。
- 执行结果:
- 核心含义:等价于
- ② |&(合并重定向到管道):
command1 |& command2
- 核心含义:等价于
command1 2>&1 | command2
,将 stdout 和 stderr 一起作为command2
的 stdin(输入),用于管道场景中传递所有输出。 - 详细示例:
bash -c 'echo out; echo err >&2' |& grep 'r'
- 执行过程:
bash -c '...'
的 stdout(“out”)和 stderr(“err”)一起传入grep 'r'
,grep
匹配含 “r” 的内容; - 执行结果:终端输出 “err”(“err” 含 “r”,“out” 不含)。
- 执行过程:
- 核心含义:等价于
4. 丢弃输出(重定向到 /dev/null)
/dev/null
是 Linux/Unix 系统中的 “黑洞文件”,任何写入该文件的内容都会被直接丢弃(不保留),用于屏蔽不需要的输出(正常输出或错误信息)。
- 核心语法:
- 丢弃 stdout:
command > /dev/null
- 示例:
echo "不需要显示的内容" > /dev/null
,终端无任何输出(内容被丢弃)。
- 示例:
- 丢弃 stderr:
command 2> /dev/null
- 示例:
ls /no/such/path 2> /dev/null
,ls
的错误信息被丢弃,终端无任何输出。
- 示例:
- 同时丢弃 stdout 和 stderr:
command > /dev/null 2>&1
(兼容所有 Shell)或command &> /dev/null
(Bash 支持)- 示例:
bash -c 'echo out; echo err >&2' > /dev/null 2>&1
,终端无任何输出(两者都被丢弃)。
- 示例:
- 丢弃 stdout:
- 适用场景:执行命令时不需要看到任何输出(无论成功或失败),如后台执行脚本时屏蔽输出:
./background_script.sh &> /dev/null &
(&
表示后台运行)。
1.5 管道(|:连接命令的 “数据流通道”)
将前一个命令的stdout作为后一个命令的stdin(标准输入),实现 “命令串联”,让多个命令协同工作,默认仅传递 stdout,
2. 流程控制
2.1 if…else 分支结构
流程控制用于改变程序 “从上到下逐行执行” 的默认逻辑,if…else
是 Shell 中最基础的分支结构,通过判断条件的 “成立(true)” 或 “不成立(false)”,执行不同的代码块,分为单支、双支、多支三种格式,核心依赖 “条件表达式”(支持数字、字符串、文件判断)实现逻辑跳转。
2.1.1 核心基础:条件表达式格式
if…else
的条件判断需通过 “括号 + 表达式” 实现,必须严格注意空格,否则会报语法错误,核心格式如下:
- 标准格式:
if [ 条件表达式 ]; then
- 说明:
[
是 Shell 内置命令(等价于test
命令),与 “条件表达式” 之间需有空格;;
用于分隔命令,then
可换行写(此时无需;
)。
- 说明:
- 支持的条件类型:
- 数字比较:使用关系运算符(如
-gt
大于、-eq
等于,详见文档 6.2),例:[ $num1 -gt $num2 ]
(判断 num1 是否大于 num2)。 - 字符串比较:使用字符串运算符(如
=
相等、-z
空字符串,详见文档 6.4),例:[ "$str1" = "$str2" ]
(判断两个字符串是否相等,变量加引号避免空格问题)。 - 文件判断:使用文件测试运算符(如
-f
普通文件、-d
目录,详见文档 6.5),例:[ -f /root/file.txt ]
(判断该路径是否为普通文件)。
- 数字比较:使用关系运算符(如
2.1.2 单支 if(仅条件成立时执行)
1. 语法结构
if [ 条件表达式 ]; then# 条件成立(true)时执行的命令
fi # 必须以 fi 结束,与 if 对应
- 执行逻辑:仅判断一次条件,若条件成立则执行
then
后的代码块;若条件不成立,不执行任何操作,直接跳过整个if
结构。
2. 关键说明
fi
是if
的反向拼写,用于标记分支结构的结束,不可省略。- 适合 “只有一种有效场景,无需处理失败情况” 的需求(如 “当文件存在时,输出提示”)。
3. 实战示例:判断数字是否为偶数
#!/bin/bash
num=100 # 定义变量 num
if [ $((num%2)) -eq 0 ]; then # 条件:num 对 2 取余等于 0(偶数)echo "$num 是偶数" # 条件成立时执行
fi
- 执行结果:终端输出
100 是偶数
。 - 若修改
num=101
,条件101%2=1
不成立,终端无任何输出。
4. 常见场景
- 检查脚本参数是否存在:
if [ -n "$1" ]; then echo "第一个参数是:$1"; fi
(若传递了参数 1,输出参数值)。 - 验证命令执行结果:
if [ $? -eq 0 ]; then echo "上一条命令执行成功"; fi
($?
表示上一条命令的退出状态码,0 为成功)。
2.1.3 双支 if…else(条件成立 / 不成立各执行不同逻辑)
1. 语法结构
if [ 条件表达式 ]; then# 条件成立(true)时执行的命令(命令1)
else# 条件不成立(false)时执行的命令(命令2)
fi
- 执行逻辑:判断一次条件,二选一执行 —— 条件成立则执行
then
块,条件不成立则执行else
块,两者必选其一,且仅执行一个。
2. 关键说明
else
无需加条件,直接处理 “所有不满足if
条件” 的情况。- 适合 “非此即彼” 的场景(如 “判断两个数字的大小,输出‘大于’或‘小于’”)。
3. 实战示例:比较两个数字的大小
#!/bin/bash
num1=$1 # 接收脚本的第 1 个参数(外部传递,如 ./demo.sh 10 5 中的 10)
num2=$2 # 接收脚本的第 2 个参数(如上述示例中的 5)
if [ $num1 -gt $num2 ]; then # 条件:num1 大于 num2echo "$num1 大于 $num2"
elseecho "$num1 小于或等于 $num2" # 条件不成立时执行(包含等于、小于两种情况)
fi
- 执行脚本:
./demo.sh 10 5
,输出10 大于 5
。 - 执行脚本:
./demo.sh 3 7
,输出3 小于或等于 7
。
4. 常见场景
- 验证用户输入:
read -p "请输入 yes 或 no:" ans; if [ "$ans" = "yes" ]; then echo "继续执行"; else echo "退出程序"; fi
。 - 检查文件是否存在:
if [ -f /root/test.txt ]; then echo "文件已存在"; else touch /root/test.txt; fi
(文件存在则提示,不存在则创建)。
2.1.4 多支 if…elif…else(多个条件依次判断)
1. 语法结构
if [ 条件表达式1 ]; then# 条件1成立时执行的命令
elif [ 条件表达式2 ]; then# 条件1不成立、条件2成立时执行的命令
elif [ 条件表达式3 ]; then# 条件1、2不成立、条件3成立时执行的命令
# ... 可添加多个 elif
else# 所有条件都不成立时执行的默认命令(可选)
fi
- 执行逻辑:从左到右依次判断条件,一旦某个条件成立,立即执行对应
then
块,且后续所有条件不再判断(“短路执行”);若所有条件都不成立,执行else
块(若省略else
,则无操作)。
2. 关键说明
elif
是else if
的缩写,可根据需求添加任意多个(但需避免条件冗余)。- 适合 “有多个层级判断,每个层级对应不同结果” 的场景(如 “根据分数判断成绩等级”)。
3. 实战示例:根据分数判断成绩等级
#!/bin/bash
score=$1 # 接收外部传递的分数参数(如 ./grade.sh 85 中的 85)
if [ $score -ge 90 ]; then # 条件1:分数 >=90echo "成绩等级:优秀"
elif [ $score -ge 80 ]; then # 条件2:分数 >=80(且 <90,因条件1已不成立)echo "成绩等级:良好"
elif [ $score -ge 60 ]; then # 条件3:分数 >=60(且 <80)echo "成绩等级:及格"
else # 所有条件不成立(分数 <60)echo "成绩等级:不及格"
fi
- 执行结果:
./grade.sh 92
→ 输出优秀
。./grade.sh 75
→ 输出及格
(因 75 <80,条件 2 不成立;75>=60,条件 3 成立)。./grade.sh 58
→ 输出不及格
。
4. 常见场景
- 按时间段输出问候语:
hour=$(date +%H); if [ $hour -lt 12 ]; then echo "早上好"; elif [ $hour -lt 18 ]; then echo "下午好"; else echo "晚上好"; fi
。 - 判断文件类型:
file=/root/demo; if [ -d $file ]; then echo "是目录"; elif [ -f $file ]; then echo "是普通文件"; else echo "是其他类型文件"; fi
。
2.1.5 常见错误与注意事项
空格问题(高频错误)
- 错误写法:
if [$num1 -gt $num2]; then
([
与变量间无空格)、if [ $num1 -gt$num2 ]; then
(运算符与变量间无空格)。 - 正确写法:
if [ $num1 -gt $num2 ]; then
([
、运算符、变量之间必须有空格)。
- 错误写法:
变量引用问题
- 字符串比较时,变量需加双引号,避免空格导致的语法错误:
错误:if [ $str = "hello world" ]; then
(若str
为空,会变成[ = "hello world" ]
,语法错误)。
正确:if [ "$str" = "hello world" ]; then
(加引号后,即使str
为空,也会解析为[ "" = "hello world" ]
,逻辑正常)。
- 字符串比较时,变量需加双引号,避免空格导致的语法错误:
数字与字符串混淆
- 关系运算符(
-gt
、-eq
等)仅支持数字,若用于字符串(非数字格式)会报错:
错误:if [ "abc" -gt "def" ]; then
(字符串不能用-gt
比较)。
正确:字符串比较用=
或!=
,例:if [ "abc" != "def" ]; then
。
- 关系运算符(
fi
不可省略- 所有
if
结构必须以fi
结束,否则 Shell 会提示 “语法错误:意外的文件结束”(syntax error: unexpected end of file
)。
- 所有
条件顺序问题(多支结构)
- 多支
if
中,条件需从 “范围大” 到 “范围小”,或从 “严格” 到 “宽松”,避免逻辑覆盖:
错误:先判断score -ge 60
,再判断score -ge 90
(此时 90 分也会触发>=60
的条件,后续>=90
不再执行)。
正确:先判断score -ge 90
,再判断score -ge 80
,最后判断score -ge 60
。
- 多支
3. 总结
命令扩展(控制命令与数据流)
逻辑运算符:按命令结果(0 = 成功,非 0 = 失败)控流程
&&
:左成功才执行右(如make && make install
)||
:左失败才执行右(如mysql || echo "连接失败"
)
echo 命令:输出内容
- 默认输到终端(stdout):
echo "hello"
- 输错误信息(stderr):
echo "err" >&2
- 默认输到终端(stdout):
文件描述符(FD):3 个核心标识
- 0 = 输入(键盘)、1 = 正常输出(终端)、2 = 错误输出(终端)
重定向:改输出目标
>
/>>
:覆盖 / 追加正常输出到文件(如echo 1 > a.txt
)2>
/2>>
:覆盖 / 追加错误输出到文件(如ls /no 2> err.txt
)>file 2>&1
/&>
:正常 + 错误输出都进文件>/dev/null
:丢弃不需要的输出
管道(|):前命令输出当后命令输入
- 例:
echo "apple banana" | grep apple
(筛选结果)
- 例:
流程控制(if…else 分支)
按条件执行不同代码,核心是[ 条件表达式 ]
(注意空格)
单支 if:条件成立才执行
- 例:
if [ $num -eq 10 ]; then echo "等于10"; fi
- 例:
双支 if…else:二选一执行
- 例:
if [ $num -gt 10 ]; then echo "大"; else echo "小"; fi
- 例:
多支 if…elif…else:多条件判断
- 例:分数评级(90 + 优秀、80 + 良好、60 + 及格、否则不及格)
关键注意:
- 数字用
-gt
/-eq
等,字符串用=
/!=
,文件用-f
(普通文件)/-d
(目录) - 变量加引号防空格问题(如
["$str" = "a"]
)
- 数字用