科技 · 實用指南
sed 顯示「unterminated s command」?先證明 Shell 與資料邊界,再增加跳脫
這個診斷只表示 sed 收到的替換程式缺少可用的結束邊界。先擷取實際參數與位元組、區分四類故障,再於不原地寫入的情況下修復並驗證。

「未終止的 s 命令」是解析器報告,不是完整診斷。抵達 sed 的替換程式在預期位置已沒有可用的結束分隔符:原始語法可能少了分隔符、資料可能含有相同分隔符、展開值可能帶有回車或換行,或更早的解析層先消耗了引號或反斜線。
從程序邊界開始。先擷取傳給 sed 的精確參數並檢視位元組,再修改跳脫。看清邊界後只修真正擁有它的那一層;在小型測試資料上不使用原地編輯,確認輸出差異完全正確後才加入平台對應的 -i。
1. 擷取 sed 實際收到的內容
以最小輸入重現並先移除 -i。Shell 追蹤只是線索;在支援的 Shell 中逐行列印已跳脫參數,再用 od 或 xxd 找出一般終端顯示會隱藏的分隔符、反斜線、回車與換行。
依序記錄每個擁有者:互動 Shell 或腳本、參數展開、命令替換、YAML 或 CI 模板、SSH 或容器包裝層,最後才是 sed。不要使用 eval,它會增加解析層並改變證據。
2. 判定破裂的邊界
若最終 sed 參數本來就沒有第三個分隔符,修正命令語法;若模式或替換資料含分隔符,改用安全分隔符或只跳脫該欄位;若值含回車或換行,先決定多行資料是否應進入此命令。
本機正確而 CI、YAML、SSH 或命令替換失敗時,逐層比較位元組。第一次產生差異的邊界才是修復位置,後面盲目增加反斜線只會掩蓋原因。
3. 分別處理模式與替換欄位
正規表示式欄位與替換欄位不是同一種語言。正規表示式元字元屬於模式決策;替換中的未跳脫 & 會插入匹配文字,反斜線會引入替換跳脫。先滿足 Shell 引用,再只套用該欄位需要的最少 sed 跳脫。
資料複雜時使用欄位專用編碼器,或從受控範本產生 sed 腳本檔。若結構化解析器或程式庫可以清楚定義邊界,就不要把不可信文字串接進 Shell 或 sed 語法。
4. 測試故障矩陣,不只測一個正常值
用小型測試檔依次測試空值、空白、所選分隔符、&、反斜線、回車、換行與不匹配值。把 stdout 與精確預期檔比較;停止報錯不等於轉換正確。
經過原先失敗的包裝層重測。終端直接成功不能驗證 YAML、SSH、容器入口或建置變數。把擷取參數與預期輸出保存為迴歸測試。
5. 差異正確後才使用就地編輯
先在副本上執行已驗收的表示式。確認 sed 實作,因 GNU、BSD 與 BusyBox 的 -i 與備份後綴形式不同;重要檔案應保留備份或原子替換流程。
真實包裝層必須送出已審核位元組、測試差異完全一致、邊界資料保持字面值,而且副本只修改一次。任何擁有者或位元組仍未知時,停在 stdout 並保存證據。
