coreutils 9.12:stat 與 env 輸出改為預設跳脫特殊字元
GNU coreutils-announce mailing list · 2026-09-14
GNU Coreutils 的 stat 和 env/printenv,把預設輸出從「直接印出原始字元」改成「依 QUOTING_STYLE 做 shell 跳脫」,stat 另外新增 %Qn 格式碼可強制跳脫檔名,env 也新增 --env0-from=FILE 用來讀回 NUL 分隔的環境變數檔。這是 Pádraig Brady 於 2026 年 9 月 14 日透過 coreutils-announce 郵件列表發布的 coreutils 9.12,距上一版 9.11 已 21 週,累積 288 次 commit、16 位貢獻者。
背景
Unix 檔名除了 / 和 NUL 之外幾乎什麼字元都合法——空白、單引號、甚至換行都是有效檔名。多年來 stat 的預設輸出卻是把 %n(檔名)原封不動印出來,遇到含換行或引號的檔名,輸出會直接斷行或打亂後續的 shell 引號配對。env/printenv 也是同樣邏輯:把 KEY=VALUE 整行印出,值本身若含換行,看起來就像多出一條環境變數,難以分辨界線在哪裡。這些輸出向來被腳本直接拿去餵給下一段 shell 指令、寫進備份索引,或用簡易文字解析器逐行讀回,卻沒有任何跳脫保護,是遇到「檔名/環境值含特殊字元」這種邊界狀況時最先出包的地方——這個缺口從 coreutils 最早期的版本就存在,ls 多年前就靠 --quoting-style 補上了,但 stat 和 env 一直沒跟進。更麻煩的是,未跳脫的檔名如果被直接組進另一段要執行的 shell 指令,攻擊者只要能控制檔名(例如上傳檔案的原始檔名),就有機會塞入分號或反引號改變指令的執行內容,這類問題在處理不受信任輸入的批次腳本裡並不罕見。
核心改動
9.12 把這兩組指令的預設輸出都換成跳脫版本,統一套用 coreutils 既有的 QUOTING_STYLE 環境變數。env/printenv 現在依 QUOTING_STYLE 決定跳脫方式,預設為 shell-escape 風格——把值包進單引號,內含的單引號再轉成 '\'' 這種可以貼回 shell 直接執行的形式;stat 則是「在需要時」自動套用同一套 shell 引號規則讓檔名跳脫更精確,並新增 %Qn 格式組合,可在任何 format string 裡強制輸出跳脫過的檔名,不受目前 quoting style 設定影響。env 另外補上 --env0-from=FILE,讓既有 env -0 印出的 NUL 分隔環境變數檔可以被讀回、重建整個環境,補上了 env -0 一直缺的「讀回」那一半,也讓含換行、含 NUL 之外任意位元組的環境值第一次能安全往返。
$ # 9.11 及之前:檔名原封不動印出
$ stat -c '%n' "o'brien's file.txt"
o'brien's file.txt
$ # 9.12:預設套用 shell 跳脫(示範 shell-escape 風格)
$ stat -c '%n' "o'brien's file.txt"
'o'\''brien'\''s file.txt'env/printenv 是同一種修法:假設 GREETING 的值含一個換行,9.11 印出來會像多一行看不出界線在哪的環境變數;9.12 起同一個值會被包進單引號一次印完,下游程式一眼就能看出這是同一個變數。
影響範圍
直接解析 stat 輸出、餵給下一段指令的腳本首當其衝:像是把 stat -c '%n' * 的結果做 for f in $(...) 這種未加引號展開,或把輸出寫進設定檔再原樣讀回的工具,遇到檔名含空白、引號時,跳脫後多出的反斜線和單引號會讓比對或路徑組合失敗。想保留舊行為的腳本,需要顯式加上 QUOTING_STYLE=literal 或 stat --quoting-style=literal。
env/printenv 的下游同樣受影響:CI 裡把 env 輸出丟給 grep/awk 做 KEY=VALUE 比對的健康檢查腳本、容器 entrypoint 裡讀環境變數的簡易 parser,都可能因為值被加上引號而比對失效。想安全備份、還原環境變數的維運腳本,則可以直接用 env -0 搭配新的 --env0-from=FILE 做往返,不用再自己處理跳脫。
另外,寫系統資訊蒐集腳本的人可以改用 uname -A/--all-labeled(一行一項,附標籤輸出),取代原本要切 uname -a 單行輸出字串的作法;stat/tail 也新增了對 failfs、nullfs 這兩種檔案系統類型的辨識,跑在這些檔案系統上的監控腳本不會再把它們誤判成未知類型。把 stat 輸出寫進測試快照(例如套件建置的可重現性測試,拿檔案權限、時間戳去跟上次結果比對)的 CI 流程,也該重新跑一次比對基準,避免只因為多了跳脫符號就誤判成回歸。