expand 是什么
expand 把制表符换成等量空格,unexpand 反过来把空格压回制表符,两者都属于 GNU coreutils。它们要解决的是「同一份文件在不同编辑器、不同工具里对齐效果不一致」的问题:Tab 的显示宽度随编辑器设置变化,空格则处处一样。unexpand 默认只处理行首空白,加 -a 才会连行内空白一起转换。
基本信息
| 所属 | GNU coreutils(各发行版默认安装) |
|---|---|
| 语法 | expand [-t 宽度] [文件] / unexpand [-a] [-t 宽度] [文件] |
| 默认制表位 | 8 列,可用 -t 改为其他宽度 |
| 观察工具 | cat -A 里 ^I 表示 Tab,行尾 $ 表示换行 |
典型使用场景
- 代码或配置多人协作时统一缩进,避免 Tab 宽度不同造成的错位
- 提交前把同事留下的 Tab 缩进统一成空格,减少无意义的 diff 噪音
- 把大段空格缩进压成 Tab,缩小老格式文件体积
- 排查缩进敏感文件(Python、YAML)里混用 Tab 与空格的问题
- 处理老系统导出的、靠 tab 对齐的固定宽度报表
- 对比两份文件差异前先做一次空白统一
常用示例
常用示例
expand -t 4 tabbed.txt > spaced.txt # Tab 换成 4 个空格
expand -t 2 config.ini > config.fixed # 统一为 2 空格缩进
unexpand -a spaced.txt > tabbed.txt # 行内连续空格也转成 Tab
unexpand --first-only spaced.txt # 只转行首空白(默认行为)
expand -t 8 file.txt | head -5 # 先看前几行效果再整体处理
cat -A file.txt | head # 看清是 Tab 还是空格
grep -P '\t' -l ./*.py # 找出含 Tab 的 Python 文件
diff <(cat -A a.txt) <(cat -A b.txt) # 对比空白差异的真实形态常用选项
| 选项 | 作用 | 说明 |
|---|---|---|
| -t N | 设置制表位宽度 | expand 默认 8,可给逗号分隔的多个位置 |
| -i | 只转换行首空白(expand) | 行内 Tab 保持原样 |
| -a | 转换所有空白(unexpand) | 不加则只处理行首 |
| --first-only | 只转换行首(unexpand) | 与默认行为一致,写出来更明确 |
| 多个文件 | 依次处理并合并输出 | 等价于先 cat 再转换 |
Makefile 的规则行必须以真实 Tab 开头:expand 或 unexpand -a 会把规则行变成空格,make 直接报 missing separator。处理 Makefile 前先确认规则,或用编辑器的缩进转换单独处理。
空格与 Tab 的转换不是无损往返:当空格数不落在制表位上时无法精确还原原始形态,来回转换会让文件内容持续变化。重要文件先提交或备份再动手。
Python 3 不允许同一文件混用 Tab 与空格缩进,YAML 同样如此。批量统一缩进后仍要跑一次语法检查或解析测试,别只看文件能不能打开。