Shell 编程基础知识总结
Shell 是用户与内核之间的命令解释器,也是把小程序拼成数据流的脚本语言。本文讲清变量与环境变量、管道与重定向背后的 fork/exec/dup2 机制、find+xargs 与 grep+awk 两组经典组合,以及脚本调试的基本功。
Shell 的定位
内核不认识 ls -l | grep log 这样的字符串。Shell 站在用户与内核之间:读入命令行,做变量替换、通配符展开、参数切分,然后调用 fork、exec 等系统调用把程序跑起来,再把结果交回终端。交互时它是命令解释器,写进文件就是脚本语言——变量、条件、循环、函数一样不缺。常见实现有 bash(主流默认)、sh(POSIX 标准)、zsh、dash 等;写脚本第一行用 #!/bin/bash 声明解释器。
变量与环境变量
Shell 变量分两类。普通变量 name="value" 只活在当前 Shell 进程里,子进程看不到;export PATH="$HOME/bin:$PATH" 导出的环境变量才会随 fork 被子进程继承——PATH、HOME 都是如此。赋值等号两边不能有空格,引用时写 "$name":不加双引号的变量会被重新分词,含空格的路径立刻出问题。
还有一组特殊变量由 Shell 维护:$? 是上一条命令的退出码(0 表示成功),$# 是参数个数,"$@" 是全部参数(保留边界,遍历参数只用它),$$ 是当前进程号。
退出码是脚本可靠性的基础:每条命令执行完都会返回状态,脚本应显式判断失败分支,而不是只看屏幕上有没有报错。例如 if ! cp a b; then echo "备份失败" >&2; exit 1; fi,比跑完再人工检查可靠得多。
管道与重定向的进程视角
ps aux | grep java 背后没有魔法,是几次系统调用的配合:
1. Shell 调用 pipe() 创建管道,得到读端、写端两个文件描述符 |
重定向同理:cmd > out.log 是子进程打开文件后用 dup2 覆盖 fd 1;2>&1 是让 fd 2 指向 fd 1 当前的目标。理解了”管道传的是字节流、走内核缓冲区、两端进程并行跑”,就能解释为什么管道前段失败默认不影响整体退出码,以及为什么脚本里几乎必开 set -o pipefail。
两组常用组合
find 配 xargs:批量处理文件
# 找出 30 天前的日志并删除 |
find 负责按条件筛文件,xargs 把输入拼成参数分批喂给后面的命令,避免”参数列表过长”。文件名可能含空格时,用 -print0 配合 xargs -0 以 NUL 分隔,是最稳的写法。
grep 配 awk:文本过滤与提取
# 找出 ERROR 日志并提取前两列与最后一列 |
grep 按行过滤,awk 按列处理——一个负责”选哪些行”,一个负责”取哪几列”。日志分析、统计报错分布,九成都逃不出这个套路。
脚本调试与健壮性
bash -n script.sh:只查语法不执行,提交前必跑。set -x:逐行打印展开后的命令,定位”哪一步开始不对”最直接;也可用bash -x script.sh整脚本开启。- 脚本开头写
set -euo pipefail:遇错退出、用未定义变量报错、管道中间失败即整体失败,把隐性错误显性化。 - 交给 shellcheck 做静态检查,未加引号的变量、错误的重定向这类常见问题它会直接指出。
小结
- Shell 是用户与内核的接口:解析命令行,用 fork/exec/dup2 组装进程与数据流。
- 普通变量不出当前进程,
export才能传给子进程;引用变量一律加双引号。 - 管道是并行进程间的字节流,重定向是文件描述符的替换。
- find+xargs 管文件批处理,grep+awk 管文本行列;调试三板斧是
bash -n、set -x、set -euo pipefail,再加 shellcheck。

