
Ubuntu 18.04 里 Terminal 打不开是个特别典型的看着像小毛病、查起来要命的故障。我这几年帮人处理过的次数多得数不清表现基本就那几种点左上角图标转两圈没动静CtrlAltT 按到手酸也不弹窗或者窗口闪一下立刻消失。很多人第一反应是重启重启完照样打不开然后就开始怀疑系统坏了、要重装。实际上绝大多数情况下问题就出在 gnome-terminal 那条启动链的某一个环节上——那个你从来没注意过的/usr/bin/gnome-terminal脚本、被换掉的 python3 默认解释器、没生成全的 locale或者一个卡死的 gnome-terminal-server 进程。下面我把自己踩过的坑和排查顺序完整拆一遍从去哪个入口敲命令一直讲到修完怎么防复发你照着走一遍基本能定位到具体那一环。1. Ubuntu 18.04 点 Terminal 没反应先分清是启动链哪一环断了1.1 从图标到 bash 提示符中间其实隔了四层很多人以为打开终端就是把一个叫 Terminal 的程序拉起来其实在 Ubuntu 18.04 的 GNOME 桌面里这条链路至少有四层。第一层是桌面入口可能是/usr/share/applications/org.gnome.Terminal.desktop这个 desktop 文件也可能就是你按下的 CtrlAltT 快捷键它俩最终都指向同一个可执行文件第二层才是真正被执行的/usr/bin/gnome-terminal注意这个文件在 Ubuntu 18.04 上并不是编译好的二进制而是一个用 Python 3 写的脚本第三层是脚本通过 D-Bus 去激活org.gnome.Terminal这个服务真正干活的进程是/usr/lib/gnome-terminal/gnome-terminal-server第四层才是 server 给你 fork 出来的那个 shell也就是/bin/bash或你$SHELL环境变量指定的东西。这四层里任何一层断了你看到的现象都是终端打不开这四个字但根因完全不同修法也完全不一样。所以排查的第一件事不是急着敲修复命令而是先把断点缩小到某一层。我一般的习惯是先看现象再决定往哪个方向查。1.2 三种表现对应三种不同的断点位置我把它总结成一张对照表你对着现象先做个初判现象大概率断在哪一层第一优先检查项点图标或按快捷键完全没反应进程列表里也看不到 gnome-terminal第二层Python 脚本还没跑起来就挂了/usr/bin/python3指向、脚本 shebang窗口闪一下立刻消失或出现一个空窗口马上关闭第四层shell 启动后立刻退出~/.bashrc、~/.profile、$SHELL弹出错误对话框或者 TTY 里手动执行报一串 GDBus 错误第三层D-Bus 激活 server 失败残留 server 进程、locale、权限图标点了转圈很久最后什么也没有第二层或第三层脚本卡在 gi 模块导入python3-gi 包是否齐全这张表不是绝对的但能帮你把搜索范围从整个系统缩到一个文件。我见过太多人一上来就sudo apt install --reinstall gnome-terminal结果因为根因在 python3 或 locale重装十遍也没用纯粹浪费时间。1.3 判断完全没反应和闪退的一个小技巧如果你还有另一个能敲命令的地方——比如 SSH 进来、VS Code 的内置终端、或者切到 TTY——可以这样区分在命令行里直接跑/usr/bin/gnome-terminal观察终端里的输出。如果它立刻返回一串 Traceback 或者 GDBus 报错那就是第二层或第三层的问题报错信息基本已经把答案写在脸上了。如果它正常返回、退出码是 0但窗口闪一下就没了那问题在第四层也就是 shell 那边。如果它跑完卡住不动、窗口也出不来那大概率是卡在 D-Bus 那一步。这一步看着简单但它决定了你后面是去查 Python 环境、查 D-Bus还是去查.bashrc。方向选对了后面通常几分钟就能定位。2. 手边没有终端时这几种方式能让你重新敲上命令2.1 CtrlAltF3 切到 TTY这是最可靠的一条路图形终端打不开的时候很多人会慌觉得我连命令都没法敲这不成了死结。其实 Linux 一直给你留了后门虚拟控制台TTY。在 Ubuntu 18.04 上图形界面默认占着 tty1你按CtrlAltF3到CtrlAltF6里的任意一个就能切到一个纯文本登录界面。输入用户名和密码登录进去就是一个完整的 shell跟图形终端里能做的事一模一样。有个细节要注意在 TTY 里输入密码的时候屏幕不会显示任何字符连星号都没有这是正常设计别以为是键盘坏了直接输完回车就行。另外 TTY 下的 locale 和图形环境可能不一致某些命令的提示会是英文这个不影响使用。修完之后按CtrlAltF1或CtrlAltF2切回图形界面具体是哪个取决于你机器上 GDM 占的是哪个 TTY一般 F1 或 F2 都行两个都按一下总能回去。TTY 这条路的价值在于它是唯一不依赖任何图形组件的入口哪怕你的 GNOME 桌面整个崩了TTY 照样能进。所以我一直建议新手至少知道有这么一个东西存在关键时刻能救命。2.2 AltF2 运行对话框、编辑器内置终端、SSH 远端登录如果你不想离开图形界面还有几种入口可以用。第一种是 GNOME 的运行对话框按AltF2会弹出一个输入框直接输入命令回车就能执行。它不会显示命令的输出所以适合用来试一下某个程序能不能起来但要拿报错信息还是得靠 TTY 或者把它重定向到文件里。第二种是代码编辑器或 IDE 自带的终端。VS Code 的集成终端用的是它自己的一套伪终端实现完全不依赖 gnome-terminalJetBrains 系列也是一样。如果你平时写代码机器上大概率装了其中之一直接打开它的终端面板就能敲命令非常方便而且输出能直接看到、能复制。第三种是从另一台机器 SSH 进来。这个不用多说只要 sshd 还在跑你就能从别的设备登录进去修。这里顺便提一句前面提到的那个sudo: a terminal is required报错本质上是 sudo 需要一个真正的 tty 来交互在没有终端的环境里执行 sudo 相关操作时就会撞上。解决办法是给 sudo 加-S从标准输入读密码或者用ssh -t强制分配一个伪终端这也是远程排障时经常要用到的技巧。2.3 用 xterm 做个临时替补如果之前装过 xterm它的依赖比 gnome-terminal 简单得多往往在 gnome-terminal 挂掉的时候还能正常起来。可以在 TTY 里执行sudo apt install xterm装完再跑xterm 就能在图形界面里得到一个能用的终端窗口。等你用 xterm 把主终端修好之后再把它卸掉也不迟。有人会问那系统里原来有没有别的终端Ubuntu 18.04 默认装的是 gnome-terminalxterm 不一定有。但如果你之前用apt装过什么工具可能会带上 xterm、terminator、tilix 之类的值得在 TTY 里用dpkg -l | grep -i term翻一下看看有没有现成的替补可用。3. Python3 被 update-alternatives 换掉gnome-terminal 打不开的头号原因3.1 为什么系统里那个 py 脚本对 python3 这么敏感这是我在 Ubuntu 18.04 上遇到过最多的一个原因而且特别隐蔽因为它通常出现在你装完某个新版本的 Python 之后。事情的来龙去脉是这样的Ubuntu 18.04 自带的 Python 3 是 3.6系统里有一大票工具——包括 gnome-terminal 的启动脚本——都是依赖这个版本、以及为 3.6 编译好的python3-gi扩展模块在跑。很多人为了跑某个新框架装了 Python 3.8 或者 3.9然后顺手用update-alternatives把系统的python3从 3.6 切到了新版本。这一步看起来只是换个默认解释器但实际影响面非常大。因为/usr/bin/gnome-terminal这个脚本的第一行是#!/usr/bin/python3它启动方式就是明确调用系统的 python3。当 python3 指向 3.8 时脚本会用 3.8 去执行而 3.8 的环境里根本没有为它编译的gi模块也就是 PyGObject于是脚本在from gi.repository import Gio, GLib这一行就直接抛ModuleNotFoundError: No module named gi退出了。用户看到的就是点图标毫无反应。同样的道理gdb、apt的部分钩子、还有各种系统级的 Python 工具都会跟着一起挂只是终端打不开是最先被发现的。3.2 现场复现三条命令确认是不是它判断这个原因我用三条命令就够都在 TTY 里执行# 第一条看 /usr/bin/python3 到底指向谁 ls -l /usr/bin/python3 # 第二条看 gnome-terminal 脚本用的是哪个解释器 head -1 /usr/bin/gnome-terminal # 第三条直接手动跑一遍看报错 /usr/bin/python3 -c from gi.repository import Gio, GLib; print(gi ok)如果ls -l的输出是/usr/bin/python3 - python3.6那基本排除这个原因如果指向python3.8、python3.9甚至python3.10那十有八九就是它了。第三条命令如果报ModuleNotFoundError: No module named gi那就彻底坐实了。我见过几次python3被指向了自己编译安装的版本那种情况下连gi的搜索路径都是乱的根本找不到。3.3 恢复方案优先走 update-alternatives别硬改符号链接确认之后恢复的思路就是把 python3 还回 3.6。如果你当初是用 alternatives 机制切过去的那就用同一套机制切回来# 先看看系统的 alternatives 里到底登记了哪些 python3 sudo update-alternatives --display python3 # 如果里面有 python3.6直接交互式切换 sudo update-alternatives --config python3 # 如果列表里压根没有 python3.6就手动登记一份进去 sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 1 sudo update-alternatives --config python3选的时候编号选对应 3.6 那一项就行。切完再跑一遍上面的检测命令确认gi能正常导入然后直接/usr/bin/gnome-terminal试试窗口一般立刻就回来了。如果你当初是直接改了符号链接、没走 alternatives那就把链接改回去# 先确认 python3.6 存在 ls -l /usr/bin/python3.* # 重建链接 sudo ln -sf /usr/bin/python3.6 /usr/bin/python3改完之后顺手检查一下/usr/bin/python3.6本身是不是还在有些手工装的 Python 会把这个位置占用掉那就得先把系统自带的 python3.6 包重新装回来sudo apt install --reinstall python3.6-minimal python3.6 python3-gi。3.4 为什么不建议动系统级 python3我理解为什么大家会去切 python3新项目要用新语法、新库。但系统级的python3在 Ubuntu 里承担的角色太重了它是给操作系统自己用的不是给你做开发的。正确的做法是给开发环境单独建虚拟环境用python3.8 -m venv或者 conda、pyenv 之类的工具让需要新版本的项目走自己的解释器系统那个 3.6 原封不动。这样你既能在项目里用新版本也不会把终端、apt 这些东西搞挂。这个坑我建议大家提前记住因为它的触发条件很常见——装个新 Python 顺便切一下默认版本——但报错现象又特别含糊就是打不开不查清楚很难把它和 Python 联系起来。4. LANG 与 locale 对不上号GTK 初始化就把进程劝退了4.1 locale 三处配置的对应关系第二个高频原因跟语言环境有关。Ubuntu 18.04 上locale 是分散在三个地方配置的任何一处不一致都可能出问题第一处是系统里实际生成了哪些 locale用locale -a能列出来第二处是/etc/default/locale里写的默认值系统登录时会读它第三处是当前 shell 里的环境变量LANG、LC_ALL、LANGUAGE用locale命令能看。理想情况下/etc/default/locale里写的那个 locale 一定是locale -a列表里存在的而且当前 shell 的LANG也跟它一致。出问题的情况通常是这样你把系统语言改成了中文/etc/default/locale里变成了LANGzh_CN.UTF-8但系统当初没生成zh_CN.UTF-8这个 locale或者生成的是别的拼写比如zh_CN.utf8。这时候 GTK 的程序在初始化时拿到的 locale 是无效的glib 会报一串Locale not supported by C library之类的警告gnome-terminal-server 有可能在初始化阶段就直接退出表现出来还是打不开。4.2 用 LANGC 和 LANGen_US.UTF-8 做对照实验判断是不是 locale 的问题最直接的办法是做对照实验。在 TTY 里分别用不同的 LANG 去启动终端# 先试一个肯定存在的 C locale LANGC LC_ALLC /usr/bin/gnome-terminal 如果这样能起来而直接跑不行那基本就是 locale 的问题。再试一下英文 localeLANGen_US.UTF-8 LC_ALLen_US.UTF-8 /usr/bin/gnome-terminal 如果英文也起不来、只有 C 能起来那说明系统里连en_US.UTF-8都没生成得先补生成。这个对照实验的价值在于它能一秒钟把 locale 这个可能性确认掉或者排除掉比翻日志快得多。4.3 重新生成 locale 并写死默认值确认是 locale 的问题之后修复分两步。先补齐需要的 locale# 查看当前生成了哪些 locale -a # 生成中英文两套 UTF-8 locale sudo locale-gen en_US.UTF-8 zh_CN.UTF-8 # 再确认一次 locale -a | grep -E en_US|zh_CN然后改默认配置。/etc/default/locale这个文件要特别注意一点里面不要出现LC_ALL。这个文件里放LC_ALL会导致它覆盖所有其他 LC_* 分类而且很多图形程序对LC_ALL特别敏感经常是它的值一不对整个程序就起不来。标准的写法是LANGen_US.UTF-8 LANGUAGEen_US:en如果要用中文LANGzh_CN.UTF-8 LANGUAGEzh_CN:zh改完退出登录再进一次或者在 TTY 里source /etc/default/locale让它对当前会话生效然后再试终端。如果用update-locale命令改会更规范sudo update-locale LANGen_US.UTF-8 LANGUAGEen_US:en它会自动处理那个文件的格式。4.4 LC_ALL 指向不存在 locale 的坑我还单独遇到过一种情况/etc/default/locale里没有LC_ALL但是用户的~/.bashrc或者~/.profile里写了一句export LC_ALLzh_CN.UTF-8而这个 locale 又没生成。这种设置比系统级的更阴因为它只在你的用户环境里生效登录图形界面时 GNOME 会读它然后 gnome-terminal 一启动就撞上无效 locale。排查的时候可以在 TTY 里跑env | grep -E LANG|LC_把当前生效的所有语言相关变量列出来挨个对照locale -a看看有没有不存在的。有的话就把它从.bashrc或.profile里删掉或者改成存在的值。我建议这些变量除非有特别需求否则不要在用户的 shell 配置里手动设置交给/etc/default/locale统一管就行。5. gnome-terminal-server 残留进程、运行时目录与磁盘空间这类次生故障5.1 gnome-terminal-server 卡死与 D-Bus 激活失败除了 python3 和 locale排第三的原因是那个驻留的gnome-terminal-server进程本身卡住了。它的工作模式是常驻的第一次打开终端时D-Bus 拉起一个 server 进程之后你每次开新窗口都是让这个已有进程再 fork 一个窗口出来。这个机制的好处是启动快坏处是一旦 server 进程因为某种原因僵死D-Bus 再去激活它就会失败表现出来就是你点多少次图标都没反应而且因为 server 是后台服务你从图标上看不出来它已经死了。判断和处理都很直接在 TTY 里执行# 看看有没有 server 进程在跑 ps -ef | grep gnome-terminal-server | grep -v grep # 有的话直接结束掉让 D-Bus 下次重新拉起一个干净的 killall gnome-terminal-server # 确认已经清干净 ps -ef | grep gnome-terminal | grep -v grep然后再去点图标试试。如果这时候能起来说明之前就是 server 卡死。这种情况在长时间不重启、且频繁开关终端的机器上更容易出现尤其是内存紧张的时候。5.2 XDG_RUNTIME_DIR 权限与 /tmp、根分区空间还有一类问题来自环境和空间。GTK 程序需要用到XDG_RUNTIME_DIR在 Ubuntu 上这个值一般是/run/user/10001000 是你的用户 ID。如果这个目录的属主或权限被改乱了比如被误操作chmod -R过或者你用的不是常规登录方式那么这个变量可能是空的或者指向一个不可写的目录GTK 初始化就会失败。检查方法# 看变量有没有值 echo $XDG_RUNTIME_DIR # 看目录属主和权限应该是 你:你权限 700 ls -ld /run/user/$(id -u)如果不对就修sudo chown $(id -u):$(id -g) /run/user/$(id -u) chmod 700 /run/user/$(id -u)空间问题也别忽略。终端启动时要在/tmp下建一些临时文件如果/tmp或者根分区满了创建失败程序也可能直接退出df -h df -h /tmp我见过一次根分区被日志文件撑到 100% 的情况现象就是所有图形程序都起不来包括终端清理完立刻恢复。这种情况还有一个特征是系统整体变慢、其他程序也开始报错算是比较容易识别的。5.3 ~/.bashrc 与 ~/.profile 里的自杀式命令如果你的现象是窗口闪一下立刻消失那重点要往 shell 这边查。终端的 shell 启动时会依次读/etc/profile、~/.profile、/etc/bash.bashrc、~/.bashrc这些文件如果里面有一句会导致 shell 立刻退出的命令窗口就会瞬间关掉。常见的几种在.bashrc里写了exit或logout写了一个无限循环没加退出条件cd到一个不存在的目录并且开了set -e或者某条命令卡在等输入上。排查的办法是把这些文件的执行过程展开来看# 逐行执行并打印看卡在哪一行 bash -x ~/.bashrc # 或者临时把配置挪走试一下终端能不能起来 mv ~/.bashrc ~/.bashrc.bak mv ~/.profile ~/.profile.bak如果挪走之后终端正常了那就是这两个文件的问题再逐段加回来定位具体是哪一句。我一般的做法是先把.bashrc里最近新加的内容注释掉因为这类问题九成都是我刚加了一段配置引起的。5.4 误改权限带来的连锁反应最后一个我想单独说因为它破坏力最大误执行sudo chmod -R 777 /或者sudo chown -R改错目录。这种情况下不只是终端整个系统的权限模型都被破坏了各种程序都会以莫名其妙的方式失败。轻度的话可以针对性地修 gnome-terminal 相关文件的权限# 正确权限应该是 root:root755 ls -l /usr/bin/gnome-terminal /usr/lib/gnome-terminal/gnome-terminal-server # 修回来 sudo chown root:root /usr/bin/gnome-terminal /usr/lib/gnome-terminal/gnome-terminal-server sudo chmod 755 /usr/bin/gnome-terminal /usr/lib/gnome-terminal/gnome-terminal-server但如果整盘都被改过那最省事的办法是用dpkg --verify找出所有被改动的包文件再逐个重装。这个操作比较重属于下策平时防住比事后修容易得多。6. 修好之后怎么避免下次再被同一块石头绊倒6.1 动 update-alternatives 之前先算清楚影响面这次排查里最值钱的一条经验就是在 Ubuntu 这种把系统工具和 Python 深度绑定的发行版上别随便改系统级的python3。update-alternatives这个命令看起来只是切个默认版本但它影响的是所有写着#!/usr/bin/python3的脚本。gnome-terminal 只是其中最显眼的一个还有一批系统工具在暗处等着挂。如果确实需要新版本的 Python用虚拟环境、pyenv、conda 都行让项目走自己的解释器。实在需要用 alternatives 管理也要先把影响面想清楚改完立刻验证几个关键工具——终端、apt、gdb——能不能正常跑有问题第一时间切回来。6.2 给自己留一个不依赖 gnome-terminal 的应急终端我现在的习惯是每台 Ubuntu 机器上都留一个备用终端。最简单的是装个 xterm它依赖少、出问题概率低。如果你写代码VS Code 的集成终端本身就是一层保险。再退一步知道CtrlAltF3能进 TTY 这件事就能让你在任何情况下都不至于完全失去命令行。这几样东西平时看起来没用但真出问题的时候它们决定了你是能自己十分钟修好还是只能干等着重装系统。6.3 把 locale 和磁盘检查加进例行清单我给自己定了个简单的例行检查每隔一段时间或者每次做了系统级改动之后跑一遍# 磁盘空间 df -h / # locale 是否与配置一致 locale locale -a | grep -E en_US|zh_CN cat /etc/default/locale # python3 指向是否符合预期 ls -l /usr/bin/python3这四条命令花不了十秒钟但能提前发现绝大多数会导致终端打不开的隐患。尤其是那个ls -l /usr/bin/python3我基本上装完任何跟 Python 有关的东西都会顺手看一眼确认它还是指向 3.6。这个动作救过我好几次比出问题之后再花半小时排查划算太多了。我个人处理这类问题的体会是Ubuntu 18.04 的终端打不开绝大多数时候不是系统坏了而是某次不经意的配置改动在启动链的某一环埋了雷。顺着 python3 解释器、locale 配置、server 进程、shell 配置这几条线走一遍基本都能找到那颗雷。与其反复重装系统不如把这条排查链路练熟以后遇到同类问题就不用再慌了。