用 SSH 連接 Ubuntu、Kubuntu 或其他 systemd 較新的 Linux 系統時,有時會在命令提示字元附近看到一串奇怪的控制字元,常見關鍵字包括 OSC 3008、systemd context、__systemd_osc_context_*。它通常不影響命令執行,但會污染終端顯示,複製日誌時也容易夾帶亂碼。
這個問題不一定只和某一個 SSH 客戶端有關。WindTerm、某些嵌入式終端、舊版終端模擬器,或者對 OSC 序列支援不完整的客戶端,都可能把本該被終端解讀的控制序列直接顯示出來。
根因通常是:遠端系統在 Bash 環境裡載入了 systemd 的 OSC 上下文鉤子,而目前 SSH 客戶端沒有正確處理這些序列。處理思路也很直接:確認這些鉤子函數存在後,把它們覆蓋成空函數,並清空 PS0。
下面給兩個辦法。第一個寫在遠端 ~/.bashrc,適合想一勞永逸處理 SSH 會話的伺服器;第二個寫在 SSH 客戶端的「登入後執行命令」裡,適合只想對某個客戶端或某個會話生效的場景。
方案一:在 .bashrc 裡按 SSH 會話攔截
這個方案的邏輯是:只要偵測到目前是 SSH 遠端會話,並且系統裡確實存在 systemd 注入的 OSC 鉤子函數,就把相關函數覆蓋成空函數,同時清空 PS0。
把下面這段加到遠端伺服器的 ~/.bashrc 末尾:
|
|
儲存後重新登入 SSH,或者在目前 shell 裡執行:
|
|
如果亂碼來自 systemd 的 OSC 鉤子,重新進入 shell 後通常就會消失。
如果還想相容特定客戶端
有些客戶端會設定自己的環境變數,例如 WindTerm 可能有 TERM_PROGRAM=WindTerm。如果你想保留這個判斷,也可以寫成更寬一點的版本:
|
|
普通 SSH 場景下,單純判斷 SSH_CLIENT、SSH_TTY、SSH_CONNECTION 已經夠用。加上 TERM_PROGRAM 只是為了覆蓋某些客戶端自己的識別方式。
為什麼這個寫法相對安全
這段配置有兩層限制。
第一層是會話判斷:
|
|
這些變數通常只在 SSH 登入會話裡出現,所以它主要影響遠端登入,不會隨便改動本機桌面終端。
第二層是函數存在性判斷:
|
|
這是一道保險。只有目前 shell 已經載入了 __systemd_osc_context_precmdline 這個函數,才會繼續覆蓋相關函數。如果系統沒有這套 systemd OSC 邏輯,這段配置不會做多餘動作。
真正被覆蓋的是這幾個函數:
|
|
它們的作用是讓相關鉤子不再輸出內容。PS0 是 Bash 在讀取命令後、執行命令前展開的提示字元變數,某些 OSC 序列正是透過它或類似機制插進去的,所以這裡也一起清空。
方案二:放到 SSH 客戶端的登入後命令裡
如果你不想改遠端伺服器的 ~/.bashrc,可以把修復動作放到 SSH 客戶端的「登入後執行命令」裡。很多終端或 SSH 客戶端都有類似功能,名字可能叫:
Command executed after authenticationPost-login commandRemote command after login登入後執行命令
填入下面這一行:
|
|
如果客戶端要求自動執行後換到新的提示行,可以在末尾按它的語法追加換行。例如 WindTerm 的 Command executed after authentication 裡,可以使用:
|
|
這裡的兩個 \n 用來讓客戶端執行清理命令後再進入新的提示行。這個寫法適合 WindTerm 這類支援認證後自動執行命令的客戶端,在 Kubuntu 24.04 環境裡測試可用。
這種方案的好處是影響範圍小:只有使用該客戶端、該會話連接時才會執行清理命令,伺服器上的 shell 配置不需要改。
兩種方案怎麼選
如果這台伺服器主要是你自己用,或者你希望所有 SSH 客戶端連進來都不再看到這類亂碼,推薦用方案一。寫進 ~/.bashrc 後,換 WindTerm、Windows Terminal、Tabby、Xshell 或其他 SSH 客戶端,都能統一處理。
如果伺服器是多人共用,或者你只想讓某個客戶端規避這個問題,推薦方案二。它不改遠端配置,也不會影響其他人的 shell 環境。
也可以先用方案二驗證問題確實能解決,再決定要不要把方案一寫進伺服器的 ~/.bashrc。
注意事項
這兩個方案只是遮蔽 systemd 的 OSC 輸出鉤子,不會修改 systemd 服務,也不會影響 SSH 登入本身。
不過,如果你正在使用支援 OSC 3008 的現代終端,並且依賴它顯示命令上下文、工作目錄或系統狀態,那麼遮蔽後這些增強提示可能會消失。普通 SSH 維運、開發機登入、伺服器管理場景通常不受影響。
另外,不建議一上來就把這類函數覆蓋寫到全域 /etc/bash.bashrc。除非你確認整台機器所有使用者都需要這個行為,否則個人環境優先放 ~/.bashrc,客戶端定向修復優先放 SSH 客戶端的登入後命令。
簡短結論
如果 SSH 連接 Linux 後出現 systemd OSC 3008 亂碼,可以按這個順序處理:
- 不想改伺服器:在 SSH 客戶端裡設定登入後執行清理命令。
- 自己的伺服器:把 SSH 會話攔截邏輯寫進
~/.bashrc。 - 多人共用伺服器:先用客戶端方案驗證,再決定是否推廣到 shell 配置。
核心就是一句話:只在 SSH 會話裡檢查 systemd 的 OSC 鉤子函數,存在就覆蓋為空函數,並清空 PS0。這樣能壓住亂碼,又盡量不影響正常終端環境。