Linux命令大全这个系列写到第五篇,这一期来聊一个几乎所有人都用过、却很少有人真正吃透的命令:clear。它排在系统设置这个分类下面,日常存在感极低,但终端交互里每一次“画面恢复干净”,背后其实都是一整套终端协议在工作。你有没有遇到过这种情况:敲了很多次 clear,屏幕还是花的;或者 clear 看起来生效了,可往上滚动,历史输出还在;又或者明明只是清个屏,结果日志文件里多出一串奇怪字符。这篇文章不打算只念一遍 man 手册,而是把它当成一个实操课题,从基本用法、底层原理,到脚本中的正确姿势和问题排查,一次性讲清楚。适合刚上手 Linux 的新手,也给那些长期被终端小毛病困扰的老手一些参考。
1. clear命令的基本操作与底层原理
1.1 基础操作,但你未必注意过细节
打开终端,输入 clear,回车,屏幕像被橡皮擦过一样恢复干净。这是大家熟悉的操作,可它的真实效果比“屏幕恢复干净”更微妙。终端里的内容实际分成两块:一块是当前窗口展示出来的可视区域,另一块是向上滚动之后能看到的历史区域,也就是常说的滚动缓冲区(scrollback buffer)。clear 命令真正做的,是向终端模拟器发送一段控制序列,让它把可视区域重置;至于历史区域动不动,要结合终端类型和命令版本来判断。
如果你足够细心,会发现同一台机器、同一个终端,有时 clear 之后连上翻都翻不出旧内容,有时又能翻到之前一大片输出。这个差异不是玄学。现代 terminfo 数据库里多了一个扩展能力 E3,对应的控制序列是\033[3J,专门用来清空滚动缓冲区。有的 clear 版本在清屏后会附带发送这段序列,有的则不会。理解这一点之后,排查很多终端相关问题时都能少绕弯路。
1.2 核心原理:clear 是终端协议的翻译官
其实 clear 本身不会“擦除”任何东西,它是一个典型的翻译程序。你告诉它“请把屏幕擦干净”,它要做的事情是:读取当前终端类型,去数据库里查到对应的清屏指令,然后把指令原样写到标准输出。真正动手擦屏幕的,是终端模拟器。
终端模拟器之所以能听懂指令,靠的是 ANSI 转义序列。所谓转义序列,就是以 ESC 字符开头的一段特殊文本,终端模拟器看到后不会把这段文本显示出来,而是执行对应动作。清屏相关的常用序列有三个:
\033[H把光标移动到左上角\033[2J清空整个屏幕\033[3J清空滚动缓冲区
在常见的 xterm 类终端上,clear 输出的大致就是这些序列的组合。用 infocmp 可以看得非常清楚:
$ infocmp -1 | grep -E "clear=|E3=" clear=\E[H\E[2J, E3=\E[3J,这里的\E就是 ESC 的另一种写法。所以“清屏”这件事,本质上是一个查询、翻译、输出的链路。打个比方:clear 像个翻译官,你叫它去把屏幕弄干净,它自己不动手,而是去查字典(terminfo),找到对方听得懂的方言(转义序列),再把方言转达给终端模拟器,终端模拟器听完才真正执行。不同终端的“方言”可能完全不同,这也是 clear 必须按终端类型查询的原因。
1.3 TERM 变量:一句环境变量让 clear 翻车
既然要查字典,那按什么条件查?答案是环境变量 TERM。TERM=xterm-256color,清屏时就去查 xterm-256color 条目;TERM=vt100,就去查古老的 vt100 条目。这个变量很重要,却也经常出问题。
我遇到过一种经典翻车场景:登录脚本或全局 profile 文件里,有人为了“统一环境”直接写export TERM=dumb。dumb 在 terminfo 里被定义为不具备清屏能力的终端类型,结果所有用户进 shell 之后敲 clear 都没反应,或者直接报错。遇到这种情况,第一件事不是换清屏命令,而是先看 TERM:
$ echo $TERM xterm-256color如果显示 dumb、unknown 或者干脆是空值,终端清屏功能基本就废了大半。临时纠正的办法很简单:
$ export TERM=xterm-256color $ clear这里先记一个结论:clear 是个老老实实的查询工具,它忠实地反映了当前环境里 TERM 变量的状态。后面排查章节还会把这个结论用起来。
2. 几种清屏方式与选型
2.1 四种常见清屏方式对照
既然明白了 clear 的原理,自然要面对一个问题:清屏到底用哪种方式最快、最稳?实际上除了 clear,日常和脚本里还有几种常见选择,它们机制不同、行为不同,适应场景也不同。
| 方式 | 机制 | 是否清滚动区 | 依赖 | 典型场景 |
|---|---|---|---|---|
| clear | 查 terminfo 后输出序列 | 视 E3 能力而定 | ncurses / terminfo | 交互终端日常使用 |
| Ctrl+L | readline 内置函数,直接发序列 | 一般不清 | bash/readline 或终端模拟器 | 日常最快的清屏 |
| reset | 发送终端复位序列并重设 stty | 视实现而定 | ncurses / stty | 终端乱码、状态错乱 |
| printf 硬编码 | 直接输出 ANSI 序列 | 自己决定 | 无 | 极简环境、脚本兜底 |
clear 的优点是省心,终端类型匹配的情况下表现稳定,且不用记转义序列。Ctrl+L 是 bash 的 readline 库提供的功能,它不用启动外部进程,因此响应更快,但它通常只清可视区,滚动历史一般保留着。reset 是另一个层面的工具,它不只是清屏,还会把字符集、显示模式、控制字符配置全部恢复默认,终端乱了的时候效果显著,但不要在跑着 vim 或 top 的会话里随手敲。printf 硬编码则完全脱离数据库,适合连 ncurses 都没有的最小系统,代价是可移植性最差,老式终端可能不认。
2.2 脚本场景:我优先选择 tput clear
写脚本时,我一般不用 clear,而是用 tput clear。原因很简单:tput 可以直接指定终端类型,不依赖当前环境变量。
# 直接用当前 TERM 对应条目 $ tput clear # 指定终端类型输出清屏序列 $ TERM=vt100 tput -T vt100 clear第二个命令在 TERM 环境变量不对时,依然能按指定类型输出正确序列。这在自动化部署、远程主机维护时很有用,毕竟脚本运行环境完全不可控。我自己的习惯是配合一个 tty 判断来用:
if [[ -t 1 ]]; then tput clear fi这段判断很值钱。脚本被定时任务执行时,标准输出往往被重定向到日志文件,此时执行清屏命令,那些转义序列会被原样写进日志,事后排查时造成很大的视觉污染。这个坑我在后面排查章节还要专门讲。
2.3 给 clear 加点个人习惯
终端使用者的日常效率,很大程度来自一些顺手的小配置。我的 .bashrc 里有这样一个别名:
alias cls='clear && printf "\033[3J"'这样执行 cls 时,除了普通清屏还会额外发送\033[3J,把滚动缓冲区一并清掉。如果系统里的 clear 本身已经支持清滚动区,这个别名只做兼容性兜底,不会造成额外影响。毕竟不同发行版的 clear 选项并不完全一样,有的支持-x(不清滚动区),有的干脆没有;用 alias 统一行为是最简单粗暴的做法。
快捷键同样值得配置。bash 默认Ctrl+L就绑定了 clear-screen,zsh 里默认也接近。如果你想重新绑定,可以这样:
# bash bind '"\C-l": clear-screen' # zsh bindkey '^L' clear-screen这类配置几乎是零成本,但对操作节奏提升非常明显。很多新手不知道,一直用 clear 加回车清屏,久而久之速度和手感都落后一截。
3. 实际工作场景中的进阶玩法
3.1 写进度条时,千万别用 clear
脚本里做进度显示,最容易想到的方案就是 clear 之后重新输出。功能上没错,视觉效果却很糟糕:屏幕会整体闪一下,看清新内容要重新适应。原因在于 clear 让终端重绘整个屏幕,而进度条其实只需要更新当前一行。
我写安装部署脚本时,更习惯用\r覆盖行首:
#!/bin/bash for i in $(seq 1 50); do printf "\r[%-50s] %3d%%" "$(printf '=%.0s' $(seq 1 $((i))) )" "$((i * 2))" sleep 0.05 done printf "\n"每轮循环都用\r把光标拉回行首,再覆盖输出新内容,完全不闪屏。需要处理多行界面时,可以用 tput cup 来定位光标:
tput cup 5 0 # 把光标移动到第6行第1列把界面更新拆成“局部定位 + 局部重写”,比整屏 clear 性能更好、视觉更稳。这里送给读者一个原则:清屏是最后手段,能局部更新就不要全屏重来。
3.2 SSH 远程会话里,clear 花屏怎么排查
远程登录后敲 clear,屏幕没能干净,常见原因有两个:本地终端模拟器与远程 TERM 不匹配,或者登录脚本把远程 TERM 改了。
排查思路很直接:先在本机执行echo $TERM看正常不正常,再在远程执行echo $TERM看有没有被改。我曾经遇到一台主机,所有交互用户都变成TERM=dumb,后来查出来是/etc/profile.d下某个脚本里写了export TERM=dumb,想统一环境,结果把所有清屏操作都废了。这种情况下 clear 和 tput clear 都会失败,因为它们查询的字典里,dumb 类型根本没有清屏能力。
临时修正:
export TERM=xterm-256color clear如果重连远程会话后问题还在,就要检查 shell 的启动文件。注意别盲目改服务器全局配置,最稳妥的做法是先在当前用户下验证,确认没问题再考虑推广。
3.3 tmux 里 clear 清不掉历史?先认清归属
在 tmux 中运行 clear,你会发现当前窗格屏幕干净了,但进入复制模式往上翻,之前的输出还在。这不是 clear 失效,而是 tmux 接管了终端的滚动缓冲区。在 tmux 里,scrollback 由 tmux 自己管理,终端模拟器层面的清滚动区序列对它无效。
想要清掉 tmux 的历史,应该用专门命令:
$ tmux clear-history如果希望每次一键完成,可以在 tmux 配置里加一行:
bind C-l clear-history按默认前缀键Ctrl-b再按Ctrl-l,就能清掉历史。很多人把普通终端里的经验直接搬到 tmux,结果发现 clear 不好用,其实只是归属问题。类似的,screen 里也有自己的历史管理逻辑,不能拿 clear 的预期去套。
3.4 登录横幅与启动脚本中的清屏策略
有些发行版登录后会打印系统提示横幅,但如果 shell 启动文件里写了 clear,一登录屏幕就空了,横幅等于白打。处理方式很常见:只在本地终端清屏,SSH 登录保留横幅。
if [[ -z "$SSH_CONNECTION" ]]; then clear fi还有一种场景是某个软件更新完,提示“按任意键继续”,脚本里直接 clear 一下无伤大雅;但如果确实需要保留终端里之前的几行输出,就应该用clear -x这类不清滚动区的模式。这里再提醒一句:systemd service 的 ExecStart 里千万不要写 clear。服务启动时标准输出基本不是终端,写了要么被丢弃,要么把转义序列写进 journal,后续排查时会非常困惑。
4. 常见问题排查与避坑实录
4.1 clear 敲了没反应:先查 TERM 再查 terminfo
遇到 clear 失效,很多人的第一反应是重装系统或者换终端,其实大部分情况只是 TERM 环境变量或者 terminfo 数据缺失。排查流程可以固定成下面这套:
# 1. 查看当前终端类型 echo $TERM # 2. 确认对应的 terminfo 条目存在 ls /usr/share/terminfo/x/xterm-256color # 3. 打印该终端类型下的清屏能力,确认有 clear 字段 infocmp -1 xterm-256color | grep 'clear='如果 terminfo 文件缺失,安装对应软件包即可。如果只是环境变量不对,临时修复就用export TERM=xterm-256color。如果你身处容器或精简系统,连 terminfo 都没有,那就只能走 tput 或 printf 硬编码方案。
4.2 SSH 意外断开之后,终端状态乱了
SSH 会话没有正常退出,直接把窗口关掉,本地终端可能还停留在应用程序设置的原始模式(raw mode)。此时敲 clear,表现可能是光标乱跳、回显错乱,甚至屏幕半清半留。这时候先不要怀疑 clear,问题在终端设备状态。
先做基础复位:
$ stty sane再根据情况执行 reset。reset 和 clear 定位完全不同:clear 只清屏,reset 会把终端模拟器里的字符集、颜色、光标、控制模式全部重置,同时附带清屏。
提示:reset 在全屏程序运行时会带来明显副作用,可能把正在显示的界面重置掉。执行前最好确认没有重要进程在前台,生产环境里操作更要谨慎。
4.3 日志文件里的怪字符:转义序列污染
有时候 grep 日志能看到\033[H\033[2J之类的片段,这是脚本在非交互执行时调用 clear 留下的转义序列。在管道或重定向场景里,标准输出不是终端,clear 依然会输出那串指令,结果污染了日志。
解决办法就是前面说的 tty 判断:
if [[ -t 1 ]]; then clear fi更干净的作法是统一封装一个函数:
clear_if_tty() { [[ -t 1 ]] && clear || true }在 cron 任务、CI 脚本和 systemd 服务里,凡是可能被输出重定向的地方,都走这个函数。它在关键时刻能省下大量排查时间。
4.4 不同终端模拟器的行为差异
clear 命令本身是查数据库的,跨终端兼容性最好。但硬编码转义序列就未必了。以\033[3J为例,有些终端模拟器完整支持清滚动区,有些选择忽略,少数会理解成别的行为。遇到一个终端里 clear 能清历史、另一个不能,先别急着骂系统,看看终端模拟器实现差异。
跨平台使用场景里,建议统一用 clear 或 tput clear,而不是在脚本里手写\033[3J。实在要手写,至少先在目标终端验证一下行为。一条命令就能看出支持程度:
$ printf '\033[2J\033[3J\033[H'如果屏幕清空且历史消失,说明这个终端对三个序列都支持。如果历史还在,说明它对\033[3J处理得不好。
4.5 精简环境中根本没有 clear 命令
容器镜像、嵌入式系统、busybox 环境里,clear 命令时常不存在。碰到 command not found 时,不要天然觉得系统坏了,它本来就是个外部程序。可以先看包管理器:Debian 系通常装 ncurses-bin,Red Hat 系装 ncurses,busybox 则一般把 clear 作为 applet 编进去。如果包都装不了,才轮到 tput clear 或 printf 转义序列兜底。
有段时间我以为 clear 是 shell 内置命令,直到在一台没有 ncurses 的机器上敲了 clear 提示 command not found,才意识到它依赖外部程序。所以精简环境里的优先顺序应该是:先装包,再用 tput,最后才是 printf 硬编码。
按惯例最后写点个人习惯。我现在在任何未知环境里敲 clear 之前,都会顺手echo $TERM,这个习惯救了我很多次。日常使用上,我更倾向 Ctrl+L 完成快速清屏,脚本中则用 tput clear,需要连滚动历史一起清理的时候就 alias 一个 cls。清屏这件事看起来不过五个字母,可一旦把它放到不同终端、不同远程环境里,背后全是细节。希望这篇实操篇能让你在下次遇到屏幕“清不掉”的时候,少一点抓狂,多一点思路。