跨平台檔案傳輸 (Linux ↔ Windows、macOS、Samba、FTP、雲端同步) 最常遇到的問題是檔案名編碼不一致:Windows 歷史使用 GBK/CP936、繁中環境用 Big5/CP950,Linux 現代預設 UTF-8。直接複製會導致中文檔名變成亂碼或問號。本文詳細說明 convmv 批次轉碼全流程、編碼偵測技巧、特殊字符處理、Samba/NFS 伺服器端預轉碼配置與驗證腳本。
# 安裝
# Debian/Ubuntu
apt install -y convmv
# RHEL/CentOS/Rocky
dnf install -y convmv
# Arch/Manjaro
pacman -S convmv
# macOS (Homebrew)
brew install convmv
convmv -f <來源編碼> -t <目標編碼> [選項] <檔案/目錄>
常用參數:
-r, --recursive 遞迴處理子目錄
--notest 實際執行重命名 (預設僅模擬顯示)
--list 列出所有支援編碼
--unescap 處理 URL 編碼 (如 %20 → 空格)
--replace 替換無法轉換字符為 _
--lower / --upper 檔案名轉大小寫
-q, --quiet 僅顯示錯誤
-v, --verbose 詳細輸出
ls -la 觀察亂碼模式
極ç)?? 或部分字符缺失
python3 -c "
import os, sys
for name in os.listdir('.'):
try:
name.encode('utf-8').decode('utf-8')
print(f'UTF-8 OK: {name}')
except UnicodeError:
for enc in ['gbk', 'gb18030', 'big5', 'cp950']:
try:
decoded = name.encode('latin-1').decode(enc)
print(f'{enc.upper()}: {name} → {decoded}')
break
except:
pass
"
file -i filename 參考用
# 1. 先模擬預覽 (無 --notest)
convmv -f gbk -t utf-8 -r /path/to/dir
# 2. 確認無誤後實際執行
convmv -f gbk -t utf-8 -r --notest /path/to/dir
# 3. 驗證
ls -la /path/to/dir
# Samba 伺服器端配置 /etc/samba/smb.conf
[global]
unix charset = UTF-8
dos charset = CP936
# 讓 Samba 自動在 UTF-8 ↔ CP936 間轉換檔案名
# 客戶端 (Windows) 看到正常中文,Linux 底層儲存為 UTF-8
若歷史遺留檔名已為亂碼,需在 Linux 端離線執行 convmv 修復。
# 1. 解壓至暫存目錄
mkdir /tmp/extract && cd /tmp/extract
unzip ../archive.zip # 或 tar xf, 7z x
# 2. 轉碼檔名
convmv -f gbk -t utf-8 -r --notest .
# 3. 重新打包
cd .. && zip -r archive_fixed.zip extract/
| 情況 | 現象 | 解決方案 |
|---|---|---|
| 檔名含不可轉換字符 | convmv 報錯 Skipping, unable to convert | 加 --replace 替換為 _,或手動重命名 |
| 檔名含換行符/控制字符 | Shell 處理困難 | find . -depth -execdir convmv -f gbk -t utf-8 --notest {} + |
| 同目錄轉碼後檔名衝突 | File exists 錯誤 | 先 convmv --lower 統一小寫,或腳本偵測衝突加後綴 |
| 符號連結目標路徑編碼 | 連結指向錯誤 | find -type l -exec sh -c 'ln -sf "$(readlink {} | iconv -f gbk -t utf-8)" {}' \; |
#!/bin/bash
# verify_utf8_filenames.sh
set -euo pipefail
TARGET_DIR="${1:-.}"
echo "=== 掃描非 UTF-8 檔名 ==="
find "$TARGET_DIR" -depth -print0 | while IFS= read -r -d '' file; do
name=$(basename "$file")
if ! printf '%s' "$name" | iconv -f utf-8 -t utf-8 >/dev/null 2>&1; then
echo "非 UTF-8: $file"
fi
done
echo "=== 檢查重複檔名 (不區分大小寫) ==="
find "$TARGET_DIR" -type f -printf "%f\n" | tr '[:upper:]' '[:lower:]' | sort | uniq -d
echo "=== 完成 ==="
convmv 檢查步驟,阻擋非 UTF-8 檔名進入製品。建立「編碼偵測 → 模擬預覽 → 實際轉碼 → 驗證零衝突」標準化流程,並從來源端 (Windows 設定)、傳輸層 (協定選擇)、儲存層 (檔案系統)、應用層 (CI/CD 守門) 全鏈路治理,即可徹底消除 Linux 環境下的中文檔名亂碼困擾。