Shell 概览
自动关联目录:Shell 概览
Shell 的一切麻烦几乎都来自同一个事实:命令在被执行前要经过多轮展开(expansion),而引号决定了哪些展开会发生。
展开顺序
1. 大括号展开 {a,b} → a b
2. 波浪号展开 ~ → $HOME
3. 参数展开 $var、${var}
4. 命令替换 $(cmd)
5. 算术展开 $((1+2))
6. 单词拆分 按 IFS 把结果切成多个词
7. 路径名展开 * ? [...]
8. 引号移除 去掉语法层面的引号单词拆分(第 6 步)是绝大多数 bug 的来源:包含空格的变量不加引号,就会被拆成多个参数。
files="a b.txt"
rm $files # 实际是 rm a b.txt —— 删错文件
rm "$files" # 一个参数引号
| 引号 | 行为 |
|---|---|
| 无引号 | 全部展开 + 单词拆分 + 通配符 |
"双引号" | 展开 $var $(cmd) $((..)),但不做单词拆分与通配符 |
'单引号' | 完全字面量,什么展开都不做 |
$'...' | 支持转义序列(\n \t) |
经验法则:变量一律加双引号;只有在确实需要拆分时才不加(而且通常有更好的写法)。
变量
name=value # 等号两侧不能有空格
echo "$name"
${name:-default} # 未定义/为空时用默认值
${name:=default} # 同时赋值
${name:?msg} # 未定义则报错退出
${#name} # 长度
${name%.txt} # 去掉尾部 .txt
${name/#old/new} # 替换开头| 特殊变量 | 含义 |
|---|---|
$0 | 脚本名 |
$1 … $9 | 位置参数 |
$# | 参数个数 |
$@ | 所有参数(加引号时保持独立:"$@") |
$* | 所有参数(合成一个字符串) |
$? | 上一条命令的退出码 |
$$ | 当前进程 PID |
"$@" 是转发参数的正确写法,$* 会把参数揉成一团。
重定向与管道
| 写法 | 含义 |
|---|---|
> file | 覆盖写 stdout |
>> file | 追加 |
2> file | stderr |
&> file / > file 2>&1 | 两者一起 |
< file | 读 stdin |
| ` | ` |
<<< "text" | here-string |
<<EOF ... EOF | here-document |
注意 cmd > out.txt 2>&1 的顺序:2>&1 必须在重定向之后,否则 stderr 指向的还是旧的目标。
还有 sudo echo x > /etc/file 这种经典问题——重定向由 shell 做,不受 sudo 影响,要用 tee:
echo x | sudo tee /etc/file > /dev/null条件与循环
if [[ -f "$path" && ! -L "$path" ]]; then
...
elif [[ "$n" -gt 10 ]]; then
...
fi
for f in *.log; do echo "$f"; done
while IFS= read -r line; do echo "$line"; done < file[[ ]] 常用判断:
| 判断 | 含义 |
|---|---|
-f -d -e -L | 文件/目录/存在/符号链接 |
-r -w -x | 可读/可写/可执行 |
-z -n | 空/非空字符串 |
== != | 字符串比较(右侧不加引号则为模式匹配) |
=~ | 正则匹配 |
-eq -ne -lt -gt | 数值比较 |
函数
log() {
printf '[%s] %s\n' "$(date +%T)" "$*"
}- 返回值用
return 0/1(0 表示成功) - 想返回字符串就用
echo+ 命令替换 - 用
local声明局部变量
常见陷阱
| 陷阱 | 说明 |
|---|---|
cd 失败继续执行 | 用 `cd dir |
| 管道吞掉错误码 | set -o pipefail |
文件名以 - 开头 | 用 -- 分隔:rm -- -file |
grep 无匹配返回 1 | 在 set -e 下会中断脚本 |
while read 在子 shell 里改变量无效 | 管道会起子 shell,改用重定向或 shopt -s lastpipe |
| CRLF 换行符 | Windows 编辑过的脚本报 ^M,用 dos2unix |
许可协议:CC BY
作者:Davids
本文链接:https://hustjjd.github.io/c2b9443f.html
更新于:2026年10月10日