聊到 Linux 命令里的“小透明”,clear 绝对排得上号。功能直白到一句话就能讲完:把屏幕清空。可作为一套 Linux 命令大全的系统设置篇,我特意把 clear 单独拎出来做一期实操,是因为它背后牵着的整套东西——TERM 环境变量、terminfo 数据库、终端类型、转义序列——恰恰是很多人在终端里栽跟头的地方。前两天帮一个同事排查问题,他写脚本时习惯性在每个函数开头 clear 一下,结果日志被塞进一堆ESC[H ESC[2J,SSH 到某些机器上又直接报TERM environment variable not set。顺着这些问题一路查下去,发现 clear 能讲的干货其实不少。这篇就分几个角度把它拆透:它按下回车之后到底做了什么、几个不常用的选项怎么用、在脚本和交互场景里怎么摆正姿势、出问题时怎么一步步排查,以及和 Ctrl+L、tput、reset 这些替代方案的取舍。不管你是刚接触 Linux,还是已经在生产环境摸爬滚打过一阵,这都值得花十分钟过一遍。
1. 按下 clear 之后发生了什么:终端、terminfo 与转义序列
1.1 clear 是个独立程序,不是 bash 内置功能
很多人下意识觉得“清屏这种小事,肯定是 shell 内部顺手处理的”。实际上 clear 是一个独立的可执行程序,在 Debian/Ubuntu 这类发行版上,它来自ncurses-bin软件包,本体通常就在/usr/bin/clear。你可以用type -a clear验证:
$ type -a clear clear is /usr/bin/clear这个细节在排查问题时会变得非常重要。比如一个精简到极致的容器里没有 ncurses 相关组件,你执行 clear 就会得到command not found。一旦你意识到 clear 不是 shell 自带的,后面很多“灵异事件”就都能说通了。
1.2 它真正做的是:查 terminfo,往 stdout 写一串序列
clear 的执行链路不长,但每一环都有讲究:
- 读取 TERM 环境变量,得到“终端类型”的名字,常见的有
xterm-256color、linux、screen、tmux-256color等。 - 根据这个名字去 terminfo 数据库里查找对应终端的能力表。terminfo 数据库一般位于
/etc/terminfo、/usr/share/terminfo,用户目录下的~/.terminfo也可以放私有条目。 - 从能力表里取出名为
clear的能力值。这个值不是布尔开关,而是一段转义序列。 - 调用 putp 这类接口把这段转义序列写到标准输出。
- 终端模拟器(或内核终端)收到序列后,按照约定执行“清屏”动作。
理解这一连串动作的关键在于:clear 并不是“操作系统把屏幕内容抹掉”,它只是往输出里扔了一段控制码,真正干活的是终端。终端模拟器本质上是一台“软件化的老式硬件终端”,它和上世纪那批 VT100 设备一脉相承,都靠解析 ASCII 控制序列来执行光标移动、清屏、着色这些操作。所以 clear 是否有效,取决于你面前这个终端认不认这段序列。
1.3 用 od 把 clear 的“真面目”打印出来
想亲眼看看 clear 发送了什么,最简单的办法是用 tput 配合 od:
$ tput clear | od -An -tx1 1b 5b 48 1b 5b 32 4a这串十六进制翻译过来就是\033[H\033[2J,拆开看是两条指令:
| 转义序列 | 含义 |
|---|---|
ESC[H | 把光标移动到屏幕左上角(home 位置) |
ESC[2J | 清除整个屏幕区域 |
ESC[J | 从光标当前位置开始清到屏幕末尾 |
ESC[3J | 清除终端的回滚缓冲区(xterm 扩展能力) |
不同终端类型的clear能力值并不完全一样。比如 Linux 内核终端(Ctrl+Alt+F1 那种控制台)的 terminfo 条目里,clear 通常是\033[H\033[J,也就是先回家、再“从现在位置清到末尾”,效果上也是全屏干净;而 xterm 兼容终端一般是\033[H\033[2J,直接清整个显示区。这就是为什么 clear 的行为依赖 TERM 环境变量——它不知道该往哪套终端说话。
1.4 屏幕、回滚区与 E3 的关系
这里必须说清楚一个最常见的误解:clear 清掉的是“当前可视的屏幕区域”,并不等于终端里所有历史内容都消失了。终端模拟器普遍维护一个回滚缓冲区(scrollback buffer),你清完屏之后,旧内容其实还在缓冲区里,滚轮往上滚、或者用 Shift+PageUp 依旧能翻出来。
真正能做到“连历史一起清掉”的转义序列是ESC[3J,它是 xterm 为清除回滚缓冲区做的扩展。这个能力在 terminfo 里有自己的条目名,叫 E3。clear 命令的-x选项,本质就是“先发送普通清屏序列,再发送 E3 序列”。这里有个前提条件:终端类型对应的 terminfo 条目里必须声明了 E3,且你用的终端模拟器实现了它。两者缺一,clear -x的效果就会打折扣。
2. 三个选项而已:-x、-T、-V 各自该什么时候用
clear 的选项少得可怜,man page 上的用法基本就一行:clear [-T type] [-x] [-V]。但选项少不代表没讲究。
2.1 -x:把回滚缓冲区一并清掉
clear -x这个选项是我日常使用频率最高的,因为绝大多数现代终端模拟器对 E3 的支持都不错。什么时候特别需要它?三种场景很典型:
- 共享终端:你要离开工位一会儿,屏幕上还留着刚才的日志、命令和输出,直接 clear 只能清掉可视区域,同事滚两下鼠标就能看到你刚才在干嘛。
- 演示录屏:给客户演示某个流程,结束后想清场,滚动区里却还挂着几屏内部信息,观感很差。
- 脚本收尾:脚本里处理过敏感信息,退出前想尽量把屏幕上的残留抹干净。
验证你的终端类型是否支持 E3,可以执行:
$ infocmp -x "$TERM" | grep E3 E3=\E[3J,有输出说明 terminfo 里声明了 E3,没有输出说明这个终端条目压根没这能力,clear -x多半只会执行普通清屏。要注意的是,infocmp -x里的-x和 clear 的-x是两回事:前者让 infocmp 显示扩展能力,后者才是清除回滚。
2.2 -T:当 TERM 不靠谱时,手动指定终端类型
clear -T xterm-256color-T的意思是不管当前 TERM 环境变量是啥,直接用你指定的终端类型去查 terminfo。这种指定在三个地方特别好用:
- TERM 丢失或写错的紧急场景。比如 SSH 到一台环境变量配置混乱的机器,
echo $TERM发现是空的,此时clear -T xterm-256color能让你先清屏,再慢慢修配置。 - 在 crontab 或无人值守脚本里,你想确保输出的是某一种固定序列,而不是依赖运行环境的 TERM。
- 调试不同终端类型下行为差异时,可以用
tput -T linux clear、tput -T vt100 clear分别看看输出有什么不同。
但请牢记:-T只是“告诉命令自己是什么终端”,并不能改变你真正在用的那个终端。你把 xterm 的清屏序列发给一个压根不认 ANSI 的老终端,对方照样忽略,该乱码还是乱码。
2.3 -V:查看版本,排查“为什么两台机器不一样”
$ clear -V clear (ncurses 6.3)你是不是也会遇到“同一段命令,A 机器正常,B 机器行为诡异”的情况?clear 的表现和它所属的 ncurses 版本、以及系统安装的 terminfo 数据都有关系。当你求助别人时,随手附上clear -V的输出,对方就能少猜很多。
3. 脚本与交互场景里的正确姿势:三个容易踩坑的用例
3.1 交互菜单:在循环顶部 clear,别在 read 之前清
很多运维脚本都会做一个交互式菜单,clear 在这里是天然的选择。典型的写法如下:
#!/usr/bin/env bash while true; do clear echo "====================" echo " 简易系统工具箱" echo "====================" echo "1) 查看磁盘使用情况" echo "2) 查看内存占用" echo "3) 查看系统负载" echo "q) 退出" echo "====================" read -r -p "请选择: " choice case "$choice" in 1) df -h ;; 2) free -h ;; 3) uptime ;; q|Q) break ;; *) echo "输入无效,请重试" ;; esac echo read -r -p "按回车返回菜单..." done把 clear 放在循环顶部,是为了让每一轮都从一个干净界面开始。这里有一个新手常犯的错:如果在每个分支执行完、错误提示还没被用户看清楚时就立刻回到循环顶部,clear 会把提示瞬间冲掉。所以我在分支运行完加了read -r -p "按回车返回菜单...",把“是否刷新屏幕”的决定权交还给用户,体验会好很多。
3.2 倒计时、进度动画:能用,但别滥用
见过有人用 clear 实现一个 10 秒倒计时,效果是这样的:
#!/usr/bin/env bash for i in $(seq 10 -1 1); do clear echo "系统将在 $i 秒后开始执行清理任务,请保存好你的工作" sleep 1 done再复杂点,做个进度条:
#!/usr/bin/env bash total=50 for ((i = 0; i <= total; i++)); do clear echo "安装进度: $((i * 2))%" printf '[' printf '#%.0s' $(seq 1 "$i") printf ' %.0s' $(seq $((i + 1)) "$total") printf ']\n' sleep 0.05 done这类循环清屏能跑,但我的经验是“能用,别滥用”。整屏 clear 的视觉代价是闪烁,循环频率高的时候眼睛会很难受,而且每次都要重绘全部内容,效率和体验都不理想。如果你只是想在同一行更新进度,更好的方案是用printf '\r'回到行首覆盖,或者用\033[1A\033[K上移一行再清除,而不是把整个屏幕推倒重来。clear 适合的永远是“整个界面都需要重绘”的场景。
3.3 脚本清屏前,先确认 stdout 是终端
这是我在实战中被坑得最惨的一次,也正好是这篇文章开头的那个故事。clear 这个命令并不检查标准输出是否连到终端,它只要能从 terminfo 里查到序列,就照写不误。于是:
$ clear > /tmp/screen.log $ cat -v /tmp/screen.log ^[[H^[[2J日志文件里就会混入看不见的转义序列。更糟的是 cron 任务里如果写了 clear,执行结果以邮件或日志形式发出来,收件人会在文本里看到一坨^[[H^[[2J。所以脚本里要清屏,标准姿势是加一道 tty 判断:
if [ -t 1 ]; then clear -x fi[ -t 1 ]的意思是“文件描述符 1(标准输出)连接到了一个终端上”。只有成立时才清屏,管你是重定向到文件、管道给别的命令还是跑在 cron 里,都不会被转义序列污染下游。
3.4 把自己常用的清屏动作做成别名与函数
clear 本身短,但不妨碍你把它封装成更顺手的工具。比如:
alias cls='clear' alias clear-all='clear -x' function cdl() { builtin cd "$@" && clear && ls --color=auto }cdl这个函数的意思是:切换目录之后清屏,再列一下当前目录内容。相当于每次跳转都给终端换一块干净的“舞台幕布”。两个细节需要提醒:alias 只会在交互式 shell 里展开,写进脚本时基本无效;如果你想在函数里调用真实的 clear,最好写成command clear,避免和别名、函数本身绕来绕去形成递归。
4. 一步一步来:clear 失灵的四种症状与完整排查链路
4.1 症状一:TERM environment variable not set
新开的容器、cron 脚本、或者某些跳板机里,执行 clear 可能直接报:
TERM environment variable not set.原因在第一节已经埋了伏笔:clear 需要 TERM 才知道自己是哪台终端。环境变量没设置,它连第一步都走不出去。排查链路是这样的:
echo "$TERM" env | grep '^TERM'如果两条都没有输出,基本坐实了。修复方式:
- 交互式终端里,往
~/.bashrc写一行export TERM=xterm-256color,重新登录生效。 - Docker 场景,优先用
docker exec -it 容器名 bash进去,-i 和 -t 会帮你把 TERM 带进去;实在不行,在 Dockerfile 里加ENV TERM=xterm。 - 脚本里做兜底可以写
export TERM="${TERM:-xterm}",但这一招要慎用,因为它可能在掩盖真正的环境问题。
4.2 症状二:clear: terminal attributes: No such file or directory
这个报错比上一条稍微隐蔽。TERM 是有值的,但 clear 告诉你它找不到“终端属性”。这通常意味着 terminfo 数据库里没有你 TERM 指定的那个条目。排查方式:
echo "$TERM" infocmp "$TERM"如果 infocmp 也报错或者输出为空,说明这个终端类型名在系统里不存在。要么是 TERM 被写成了奇怪的值,要么是系统缺 terminfo 数据。常见的修复手段有两个方向:
- 把 TERM 修正为一个系统里确实存在的条目,比如
xterm-256color。 - 补装 terminfo 数据。在 Debian/Ubuntu 系上,clear 命令本体来自
ncurses-bin,基础 terminfo 条目由ncurses-base提供,更多终端条目单独打包在ncurses-term。如果连xterm这种常见类型都查不到,先看看这几个包装没装齐。
4.3 症状三:屏幕出现 ^[[H^[[2J 一类的“乱码”
明明执行了 clear,屏幕没清,反而冒出一串^[[H^[[2J一样的东西。看到这个现象,先别慌——转义序列没有被接收方解读为控制指令,而是被当成了普通文本打印出来。常见原因有三个:
- 输出被重定向了,接收方是文件或管道,不是终端,自然不会执行清屏。
- 你连的终端比较老,根本不支持
ESC[H ESC[2J这套 ANSI 序列。 - TERM 指定的类型和实际终端不匹配,你把 xterm 的序列发给了一台只能理解少量控制码的终端。
验证手段:
tput clear | cat -v test -t 1 && echo "stdout is tty" || echo "stdout is not tty"第一条命令能让你看清楚当前终端类型下 clear 到底发送什么;第二条判断标准输出到底连没连终端。如果是脚本里的问题,回到 3.3 的做法,加 tty 判断;如果是老终端,去修正 TERM 到对方真正支持的条目,比如vt100或ansi。
4.4 症状四:执行成功,但“没清干净”
clear 没报任何错,屏幕也空了,但一滚鼠标旧内容全回来了。这就是前面反复强调的“清屏不等于清回滚”。处理方式按你的实际环境分情况:
- 普通终端模拟器:用
clear -x,前提是参考 2.1 检查 E3 是否存在于 terminfo。 - tmux 里:tmux 自己管理回滚缓冲区,
clear -x发出去的 E3 不一定能渗透到 tmux 那一层。想清当前 pane 的滚动历史,用tmux clear-history。 - 程序用了 alternate screen(比如 vim、less、top 退出后的那个界面):不少终端对 alternate screen 的滚动区处理方式不同,属于正常现象。
排查命令还是那一句:
infocmp -x "$TERM" | grep -E 'clear|E3'结果能直接告诉你终端条目里有没有 E3。
4.5 症状速查表
| 症状 | 常见原因 | 快速验证 | 处理方向 |
|---|---|---|---|
| TERM environment variable not set | TERM 未设置 | echo $TERM为空 | 设置 TERM 到 xterm-256color 等 |
| terminal attributes: No such file or directory | terminfo 缺该终端条目 | infocmp $TERM失败 | 换 TERM 或装 ncurses-term |
屏幕出现^[[H^[[2J字样 | 接收方不是终端 / 终端太老 | tput clear | cat -v | 加 tty 判断、修正 TERM |
| 清屏后回滚还有内容 | 没用 -x 或 E3 不支持 | infocmp -x $TERM | grep E3 | 用 clear -x 或终端快捷键 |
| clear 行为怪得离谱 | 被 alias/函数遮蔽 | type -a clear | 用command clear绕开 |
排查这类问题,我一般先跑type -a clear确认这是一个真实程序而不是被某个奇怪别名劫持了,再按表格从上到下走一遍,基本不会卡住。
5. 不止 clear:Ctrl+L、tput、printf 转义和 reset 怎么选
5.1 五个方案,一眼看清楚
| 方案 | 是否能清回滚 | 外部依赖 | 最佳适用场景 |
|---|---|---|---|
| clear | 默认否,加 -x 视 E3 | ncurses / terminfo | 日常交互使用 |
| Ctrl+L | 否 | readline / 终端自带 | 交互式环境最顺手 |
| tput clear | 否 | ncurses / terminfo | 脚本里需要显式控制时 |
| printf 转义 | 否 | shell 内建,零依赖 | 精简容器、救援环境 |
| reset | 视终端支持 | ncurses / terminfo | 终端状态混乱时恢复 |
5.2 逐个说透使用细节
Ctrl+L 是我在交互终端里用得最多的方式。它在 bash 的 readline 里被定义为“清屏并重绘当前输入行”,好处是不需要敲命令,而且不会把你正在草拟的那条命令抹掉。从终端协议角度讲,Ctrl+L 发出的其实是 ASCII 0x0C(换页符),很多终端仿真器收到后也会清屏。它和 clear 最大的区别是基本不碰回滚缓冲区。
tput clear 和 clear 是同源工具,都是从 ncurses 里出来的。脚本里写tput clear的好处是你可以拿到返回码,万一 terminfo 有问题,tput 会返回非零值,方便脚本分支处理。配合-T还能指定终端类型:tput -T xterm clear这句在 TERM 缺失的脚本里堪称急救方剂。
printf 转义是我在精简环境里的首选。printf '\033[H\033[2J'不依赖任何外部程序,因为 printf 是 shell 内建功能。哪怕容器里连 ncurses 都拆了,只要 shell 还在,这句就能清屏。想顺手清回滚,可以手动补上\033[3J:
printf '\033[H\033[2J\033[3J'代价是它不查 terminfo,固定发送 ANSI 序列,遇到老终端可能不被认。所以我把 printf 方案定位为“最小环境兜底”,而不是日常首选。
reset 则完全是另一个赛道的工具。它不只会清屏,还会把终端属性恢复成默认:颜色方案、光标形态、自动换行、stty 参数等全都会被重置。当你用cat读了一个二进制文件导致终端乱码、或者程序异常退出把终端模式搞坏时,reset 比 clear 有用得多。副作用是执行时屏幕上可能闪一下,因为终端收到的是完整重置序列。
5.3 实战选择建议
我的习惯是分场景对待:交互式终端里能按 Ctrl+L 就不敲 clear;写交互脚本时用 clear 刷新菜单界面,但调用前先[ -t 1 ]判断;进到精简容器或救援模式时,直接用printf的转义序列;终端已经显示乱码了,就别抠 clear 了,直接reset或者先stty sane再reset。说到底这些方法不是竞争关系,而是互相补位的工具箱。
6. 几个我实际踩过的小坑:写给同样在终端里折腾的人
6.1 日志文件里的 ESC 序列
这是我踩得最实的一个坑。某次我维护一个部署脚本,里面放了一个clear当作“阶段性分隔符”。脚本正常跑的时候屏幕确实清爽,但我把输出重定向到日志之后,整个日志文件里全是^[[H^[[2J。最初我以为是脚本逻辑出了问题,最后发现就是 clear 不看 stdout 是不是终端,照写转义序列。从那之后,我写任何脚本里的 clear 都会套上 tty 判断。
6.2 clear 不是安全擦除
被 clear 清掉的只是显示内容,不代表信息消失。shell 的命令行历史还在,终端模拟器如果开启了会话日志,那玩意儿也不归 clear 管。在共享终端上处理过密码、密钥内容这些敏感信息时,光清屏远远不够。密码输入要养成用read -s的习惯,操作结束后的终端,该登出就登出。别指望 clear 能当橡皮擦。
6.3 别名递归与“怎么又不生效”
我给 clear 做过alias clear='clear -x',在交互 shell 里用着挺顺,可一旦把它放进脚本,alias 根本不展开,行为立刻“退化”成普通 clear。后来我改成函数就稳定多了:
function clear() { command clear -x }函数默认在子 shell 和非交互 shell 里也能工作,command关键字用来跳过函数名解析,直接找到真正的/usr/bin/clear,彻底避开“命名遮蔽”的麻烦。
6.4 版本差异:别拿 A 机器的经验武断 B 机器
同一条clear -x,在装了不同版本 ncurses 的机器上,可能一个清了回滚,一个只是普通清屏。原因可能是 terminfo 条目里 E3 的有无,也可能只是终端模拟器支持程度不同。我在排查这类问题时养成了一个习惯:先把clear -V和infocmp -x "$TERM" | grep -E 'clear|E3'的输出贴出来再聊结论,比靠玄学排除快得多。
说回我自己,现在日常操作里反而很少专门敲 clear 了——交互时 Ctrl+L 更顺手,写脚本时用固定序列的 printf,只有排查问题、整理演示现场时才认真研究 clear 的-x、-T和-V。工具不在多,把每个命令背后那条链路搞清楚,比背一百个命令名有用得多。希望这篇实操拆解,能让你下次再看到那个不起眼的 clear 时,想起它背后还有一整台“虚拟终端”在默默听你指挥。