在 Shell 腳本、日誌輪轉、臨時資料清理等場景,需要快速將檔案內容歸零而保留檔案本身(inode、權限、硬連結不變)。本文匯總 5 種常用清空技巧,分析各自原理、效能與適用場景,並說明為何 echo "" > file 並非最佳選擇。
| 指令 | 原理 | 效能 | Shell 相容性 | 備註 |
|---|---|---|---|---|
: > filename |
冒號內建命令(真值)無輸出,重導向截斷檔案 | 極快(無子進程、無輸出) | Bash/Zsh/Ksh/POSIX sh | 推薦首選,語意清晰 |
> filename |
Bash/Zsh 空命令重導向(僅重導向無命令) | 極快 | Bash/Zsh(非 POSIX) | 最短寫法,移植性稍弱 |
true > filename |
true 命令成功退出無輸出,重導向截斷 |
快(單一內建/外部命令) | 全 POSIX 相容 | 可讀性佳,: 別名 |
cat /dev/null > filename |
讀取空裝置輸出重導向 | 較慢(開啟 /dev/null、cat 進程) | 全 POSIX 相容 | 傳統寫法,語意明確「讀取空裝置」 |
echo -n > filename |
echo 輸出空字串(-n 抑制換行)重導向 |
慢(echo 解析、子進程) | 行為差異大(內建/外部、-n 支援) | 不推薦,可能殘留換行符 |
truncate -s 0 filename |
系統呼叫 ftruncate() 直接縮減檔案大小 |
極快(核心級操作) | GNU coreutils / Linux | 可精確指定大小,支援稀疏檔案 |
# 建立 100 MB 測試檔
dd if=/dev/zero of=testfile bs=1M count=100
# 效能比較(time 指令)
time : > testfile # real 0.001s
time > testfile # real 0.001s
time true > testfile # real 0.001s
time cat /dev/null > testfile # real 0.002s
time echo -n > testfile # real 0.002s
time truncate -s 0 testfile # real 0.001s
差異在微秒級,對單檔操作無感知;但批次處理成千上萬檔案(如 find /var/log -name '*.log' -exec truncate -s 0 {} \;)時,truncate 與 : 顯著優於 cat/echo。
cp /dev/null filename(建立新 inode)或 fallocate -p -o 0 -l 0 filename(punch hole,需檔案系統支援 FALLOC_FL_PUNCH_HOLE,ext4/XFS/Btrfs 支援)。cp /dev/null /var/log/app.log(配合 logrotate 的 copytruncate)或發送信號讓服務重新開啟日誌(kill -USR1 $(cat /var/run/app.pid))。sudo truncate -s 0 /var/log/syslog 或 sudo sh -c ': > /var/log/syslog'(注意重導向在 root shell 執行)。cat /dev/null > file 可用於管線終端 cmd | cat /dev/null > file(雖無實際意義),而 : > file 不能用於管線右側。# 方式 1:truncate(推薦,可處理特殊檔名)
find /var/log -type f -name '*.log' -exec truncate -s 0 {} +
# 方式 2:冒號重導向(需 sh -c 包裹重導向)
find /var/log -type f -name '*.log' -exec sh -c ': > "$1"' _ {} \;
# 方式 3:配合 logrotate 規則(生產環境標準做法)
logrotate -f /etc/logrotate.conf
日常互動操作,**: > filename** 最佳平衡了速度、相容性與可讀性;**truncate -s 0 filename** 適合腳本化批次處理與精確大小控制;**cat /dev/null > filename** 僅作教學展示。切記:清空內容 ≠ 釋放空間,生產日誌清空請遵循 logrotate 或服務重開機制,避免資料遺失與服務異常。
