教學:microsoft/coreutils — Windows 原生 UNIX 工具集完整指南

第 1 章:專案定位與價值主張

這個專案解決什麼問題?

長久以來,Windows 使用者若想使用 lsgrepfindcat 等 UNIX 核心指令,必須仰賴 WSL (Windows Subsystem for Linux)、Cygwin、Git Bash 或 MSYS2 等額外環境。這些方案各有限制:WSL 需要完整 Linux 子系統、Cygwin 相容層效能開銷大、Git Bash 指令集有限。

microsoft/coreutils 是 Microsoft 官方推出的解決方案——將 uutils/coreutils(GNU coreutils 的 Rust 重寫版)連同 findutils 與 grep 打包為單一原生 Windows 執行檔 (native binary),無需虛擬化層、無需相容層、無需 Linux kernel。

關鍵特色

  • 原生 Windows binary:Rust 編譯的 .exe,不需要額外 runtime
  • 70+ 指令:coreutils + findutils + grep 一次到位
  • WinGet 安裝winget install Microsoft.Coreutils 一行搞定
  • DOS 相容findsort 自動偵測 DOS/GNU 語法,不破壞既有 Batch script
  • PowerShell 7.4+ 整合:修正引號解析、處理 alias 衝突
  • MIT License (MIT 授權):可自由使用於商用環境

誰適合使用?

角色使用情境
跨平台開發者在 Windows、Linux、macOS 間切換時保持一致的 CLI 體驗
DevOps / SREWindows CI/CD pipeline 中使用 UNIX 工具
系統管理員替代笨重的 Cygwin / Git Bash
Batch / PowerShell 使用者漸進式引入 UNIX 工具,不破壞既有腳本
教育訓練在 Windows 環境學習 UNIX 指令

第 2 章:安裝指南

方法一:WinGet(推薦)

1# 安裝
2winget install Microsoft.Coreutils
3
4# 驗證
5coreutils --version
6# 預期輸出:coreutils 2026.5.29 (multi-call binary)
7
8# 列出所有可用指令
9coreutils --list

方法二:從 Release 下載

  1. 前往 Release Page
  2. 下載 .exe 安裝檔
  3. 執行安裝精靈,可選擇:
    • 加入系統 PATH
    • find 預設使用 GNU 版本或 DOS 版本
    • sort 預設使用 GNU 版本或 DOS 版本

方法三:從原始碼編譯

 1# 前置條件
 2# - Rust 1.88.0+
 3# - Visual Studio Build Tools (MSVC)
 4# - git
 5
 6# 取得原始碼(含 submodule)
 7git clone --recurse-submodules https://github.com/microsoft/coreutils.git
 8cd coreutils
 9
10# 編譯(Release 模式)
11cargo build --release
12
13# 執行檔位於 target/release/coreutils.exe

安裝後驗證

 1# 確認 PATH
 2where.exe ls
 3# 預期:C:\Program Files\coreutils\cmd\ls.exe
 4
 5# 測試基本指令
 6ls --version
 7grep --version
 8find --version
 9
10# 列出所有 70+ 指令
11coreutils --list | wc -l

解除安裝

1winget uninstall Microsoft.Coreutils

第 3 章:核心架構解析 (Architecture Deep Dive)

整體架構

microsoft/coreutils 採用 multi-call binary (多重呼叫二進位) 架構——所有 70+ 個指令編譯進同一個 coreutils.exe,安裝時以 hardlink (硬連結) 建立各指令的 .exe(如 ls.execat.exe),因此看似 700MB 的安裝目錄實際只佔一份二進位檔的空間。


graph TB
    subgraph "使用者輸入"
        CMD["cmd.exe
ls -la"] PS["PowerShell 7.4+
ls -la"] end subgraph "指令分派層 (main.rs)" ENTRY["coreutils.exe 入口
(multi-call binary)"] NAME["檔名解析
binary_path() → name()"] MAP["phf::OrderedMap
util_map() 查表"] end subgraph "啟發式分流 (nthelpers.rs)" FIND_H["find_heuristic()
DOS /C /I vs GNU -name -type"] SORT_H["sort_heuristic()
DOS /R vs GNU --reverse"] REG["Windows Registry
DefaultFind / DefaultSort"] end subgraph "上游實作 (deps/)" UU_CORE["uutils/coreutils
70+ Rust 指令"] UU_FIND["uutils/findutils
find + xargs"] UU_GREP["uutils/grep
grep + egrep + fgrep"] NT_FIND["ntfind (Rust)
DOS find 相容"] NT_SORT["ntsort (C)
DOS sort 相容"] end subgraph "PowerShell 整合" PWSH["pwsh-install.ps1
Profile 注入"] TMPL["pwsh-install-template.ps1
PSReadLine 修正"] end CMD --> ENTRY PS --> ENTRY ENTRY --> NAME NAME --> MAP MAP -->|"find"| FIND_H MAP -->|"sort"| SORT_H MAP -->|"其他指令"| UU_CORE FIND_H -->|"DOS 風格"| NT_FIND FIND_H -->|"GNU 風格"| UU_FIND FIND_H -->|"不確定"| REG REG -->|"DefaultFind=0"| NT_FIND REG -->|"DefaultFind=1"| UU_FIND SORT_H -->|"DOS 風格"| NT_SORT SORT_H -->|"GNU 風格"| UU_CORE SORT_H -->|"不確定"| REG UU_GREP -.->|"獨立 crate"| MAP PWSH -.->|"安裝時執行"| PS TMPL -.->|"注入 profile"| PWSH

Multi-call Binary 運作原理

  1. 進入點main() 取得執行檔路徑(例如 C:\...\ls.exe
  2. 名稱解析name() 擷取檔名 stem(ls
  3. 查表分派:在編譯時期透過 build.rs + phf_codegen 產生的 perfect hash map 中查找對應的 uumain 函式
  4. 執行:呼叫該指令的 uumain(args) 並以其回傳值作為 process exit code

find/sort 啟發式分流詳解

nthelpers.rs 中的 find_heuristic() 實作了精巧的命令列分析:

偵測到的 pattern判定結果
/C, /I, /N, /V 等 DOS switch→ DOS find (ntfind)
-name, -type, -exec, (, ) 等 GNU expression→ GNU find (findutils)
引號開頭的第一個參數(無 backslash escape)→ 可能是 DOS(搜尋字串)
backslash escape (\")→ GNU style
都不符合→ 查 Registry DefaultFind

建置流程

build.rs 執行三件事:

  1. generate_uutils_map():解析 Cargo.toml 中所有 uu_* 依賴,透過 phf_codegen 產生靜態 hash map
  2. compile_ntsort():用 cc crate 編譯 deps/ntsort/sort.c(原生 Windows sort 相容層)
  3. compile_manifest():嵌入 Windows 應用程式 manifest 與圖示

第 4 章:使用方式詳解

基本檔案操作

 1# 列出檔案(含隱藏檔、詳細資訊、人類可讀大小)
 2ls -lah
 3
 4# 複製檔案(遞迴、保留屬性)
 5cp -rp source_dir/ dest_dir/
 6
 7# 移動/重新命名
 8mv old_name.txt new_name.txt
 9
10# 刪除(遞迴、強制)
11rm -rf temp_dir/
12
13# 建立目錄(含父目錄)
14mkdir -p path/to/new/dir
15
16# 建立空檔案或更新時間戳記
17touch newfile.txt

文字處理

 1# 檢視檔案內容(附行號)
 2cat -n config.txt
 3
 4# 取前/後 N 行
 5head -20 large_log.txt
 6tail -f running.log
 7
 8# 搜尋文字(遞迴、忽略大小寫、顯示行號)
 9grep -rin "error" logs/
10
11# 排序與去重
12sort data.csv | uniq -c | sort -rn
13
14# 欄位擷取
15cut -d',' -f1,3 data.csv
16
17# 字元替換/刪除
18cat file.txt | tr 'a-z' 'A-Z'
19cat file.txt | tr -d '\r'  # 移除 CR 字元
20
21# 字數/行數統計
22wc -l *.txt

搜尋檔案

1# GNU find 語法
2find . -name "*.log" -type f -mtime -7
3
4# 搭配 xargs 批次處理
5find . -name "*.tmp" -print0 | xargs -0 rm -f
6
7# 結合 grep 全文搜尋
8find . -name "*.py" -exec grep -l "import torch" {} +

Pipeline 與資料處理

 1# 統計各副檔名的檔案數量
 2find . -type f | sed 's/.*\.//' | sort | uniq -c | sort -rn
 3
 4# CSV 處理:取第 2 欄、排序、去重
 5cut -d',' -f2 data.csv | sort | uniq
 6
 7# 產生序列
 8seq 1 100 | shuf | head -10
 9
10# Base64 編解碼
11echo "Hello World" | base64
12echo "SGVsbG8gV29ybGQK" | base64 -d

Windows 特有注意事項

事項說明解決方式
CRLF 換行Windows 文字檔使用 \r\ntr -d '\r' 或注意 $ 匹配
/dev/nullWindows 無此裝置檔使用 NUL 替代
無 POSIX signalsSIGHUPSIGPIPECtrl+C (SIGINT) 正常運作
路徑分隔符/\ 都可用部分指令輸出 \,影響 piping
Symlink 權限讀取不需提權建立需 Developer Mode 或管理員
PowerShell escape仍是 ` 而非 \find . `( -name "*.txt" `)

第 5 章:應用場景

場景一:跨平台 CI/CD Pipeline

 1# GitHub Actions — Windows runner 使用 UNIX 指令
 2jobs:
 3  build:
 4    runs-on: windows-latest
 5    steps:
 6      - run: winget install Microsoft.Coreutils --accept-package-agreements
 7      - run: |
 8          find src/ -name "*.rs" | wc -l
 9          grep -r "TODO" src/ | tee todos.txt
10          cat todos.txt | wc -l

場景二:開發者日常工作流

 1# 快速查看 Git 專案結構
 2find . -maxdepth 2 -type f -not -path './.git/*' | head -30
 3
 4# 搜尋所有 Python 檔案中的 import
 5grep -rn "^import\|^from" --include="*.py" .
 6
 7# 批次重新命名
 8ls *.jpeg | while read f; do mv "$f" "${f%.jpeg}.jpg"; done
 9
10# 統計程式碼行數(排除空行與註解)
11find src/ -name "*.rs" -exec cat {} + | grep -v '^\s*$' | grep -v '^\s*//' | wc -l

場景三:系統管理

 1# 找出大檔案
 2find C:\ -type f -size +100M 2>NUL
 3
 4# 磁碟用量分析
 5du -sh *
 6
 7# 系統資訊
 8uptime
 9hostname
10nproc
11df -h

場景四:取代 Cygwin/Git Bash

功能CygwinGit Bashmicrosoft/coreutils
安裝大小數百 MB~數 GB~300 MB~15 MB(單一 binary)
啟動速度慢(相容層)中等快(原生)
指令完整度最完整有限70+ 常用指令
DOS 相容find/sort 自動分流
官方支援社群Git 團隊Microsoft

第 6 章:資安掃描報告

掃描範圍

  • 掃描對象:src/(Rust + PowerShell)、build.rsCargo.tomldeps/ntsort/sort.cdeps/ntfind/coreutils.iss
  • 掃描項目:eval/execunsafe 區塊、硬編碼機密、網路呼叫、Registry 操作、PowerShell injection

綜合評級:🟢 低風險

詳細發現

1. unsafe 區塊(Rust)— 🟡 已知風險,合理使用

共 12 處 unsafe 使用,全部為 Windows API FFI 呼叫所必需:

檔案用途風險評估
main.rs L240-257GetConsoleOutputCP / SetConsoleOutputCP低:標準 Win32 API
main.rs L262-263ntsort_main FFI 呼叫中:C 函式呼叫,但參數有檢查
main.rs L297String::from_utf8_unchecked低:由 from_utf8_lossy 確認後才走此路徑
nthelpers.rs L12-13wcslen FFI低:標準 C runtime
nthelpers.rs L41-52, L251-262RegGetValueW Registry 讀取低:唯讀操作
nthelpers.rs L56-59GetCommandLineW 命令列讀取低:標準 Win32 API

評估:所有 unsafe 用法都是 Windows 平台 FFI 的必要模式,沒有任意記憶體操作或不受控的指標運算。

2. PowerShell 腳本 — 🟢 安全

  • pwsh-install.ps1:修改 PowerShell profile 檔案,使用 atomic write(先寫 .new 再 rename)
  • Invoke-Expression、無 iex、無動態程式碼執行
  • 使用 Set-StrictMode -Version 2.0 嚴格模式
  • Registry 操作限於 HKLM:\SOFTWARE\Microsoft\coreutils 自有路徑

3. C 程式碼 (ntsort) — 🟡 注意

  • deps/ntsort/sort.c 共 2,498 行,為原生 Windows DOS sort 指令的相容實作
  • 使用 NDEBUG 定義(停用 assert)
  • 為純本地排序工具,無網路操作

4. 網路呼叫 — 🟢 無

  • reqwesthyperTcpStream 等網路依賴
  • 無 HTTP client,不連外部服務
  • 所有 URL 出現均為文件中的參考連結

5. 機密資料 — 🟢 未發現

  • 無硬編碼密碼、API key、token
  • .env 載入邏輯
  • 無認證/授權相關程式碼

6. 供應鏈安全 — 🟢 良好

  • 上游為知名開源專案(uutils),Microsoft 維護 fork
  • 依賴均為成熟 Rust crate(clap, phf, textwrap, itertools)
  • 使用 git submodule 鎖定上游版本

總結

類別評級說明
程式碼注入🟢無 eval/exec/動態執行
記憶體安全🟡12 處 unsafe(FFI 必要)
網路安全🟢純離線工具
機密管理🟢無機密資料
供應鏈🟢Microsoft 官方 + 成熟上游
權限🟢安裝需管理員,執行不需

第 7 章:FAQ(常見問題)

Q1: 與 WSL 有什麼不同?

WSL 執行完整 Linux kernel 與 userspace,佔用更多資源、需要 Hyper-V 支援。microsoft/coreutils 是原生 Windows binary,啟動速度更快、資源消耗更低,但僅提供 CLI 工具子集(無 systemd、無 apt、無 Linux-only API)。

Q2: 會破壞我的 Batch script 嗎?

不會——findsort 使用啟發式分析 (heuristic analysis) 自動偵測 DOS 或 GNU 語法。若使用 /C/I 等 DOS 旗標,會自動呼叫 DOS 相容版本。安裝時也可選擇預設行為。

Q3: PowerShell 的 ls 會被覆蓋嗎?

PowerShell 的 lsGet-ChildItem 的 alias (別名)。安裝後透過 PSReadLine 整合處理衝突,但 Get-Command ls 仍會顯示 built-in。實際行為取決於 PATH 順序。

Q4: 支援 Windows 10 嗎?

是的,最低支援 Windows 10。但有一個已知問題:#49 回報 Windows 10 安裝失敗,可能與 GetTempPath2 API(Windows 11 新增)有關,PR #51 正在修復中。

Q5: 有哪些指令故意不包含?

kill(無 POSIX signals)、chmod/chown(POSIX-only 概念)、whoami(衝突 Windows 內建)、more/dir/expand(衝突 DOS 內建)。完整列表見 README 的 “Intentionally dropped” 段落。

Q6: 如何回報 Bug?

直接在 GitHub Issues 開 issue,或提交 PR。若 bug 在上游 uutils 中也存在,建議先到上游修復。


第 8 章:進階技巧

1. 透過 Registry 切換 find/sort 預設行為

1# 設定 find 預設為 GNU find(而非 DOS find)
2reg add "HKLM\SOFTWARE\Microsoft\coreutils" /v DefaultFind /t REG_DWORD /d 1 /f
3
4# 設定 sort 預設為 GNU sort
5reg add "HKLM\SOFTWARE\Microsoft\coreutils" /v DefaultSort /t REG_DWORD /d 1 /f
6
7# 還原為 DOS find/sort(值 = 0 或刪除)
8reg delete "HKLM\SOFTWARE\Microsoft\coreutils" /v DefaultFind /f

2. 處理 CRLF 問題

1# 移除 CR 字元,將 CRLF 轉為 LF
2cat file.txt | tr -d '\r' > unix_file.txt
3
4# uniq 前先正規化換行
5cat data.txt | tr -d '\r' | sort | uniq

3. 使用 multi-call binary 模式

1# 直接透過 coreutils.exe 呼叫
2coreutils ls -la
3coreutils grep -r "pattern" .
4coreutils find . -name "*.txt"
5
6# 列出所有可用指令
7coreutils --list

4. 建立自訂 alias

1# 在 PowerShell profile 中加入
2function ll { ls -lah @args }
3function la { ls -A @args }
4function grep { coreutils grep --color=auto @args }

5. 效能最佳化:善用 pipeline

1# 用 find + xargs 取代 foreach 迴圈,利用 parallel execution
2find . -name "*.log" -print0 | xargs -0 -P 4 grep -l "ERROR"
3
4# 避免不必要的 cat(Useless Use of Cat)
5# 不好:cat file.txt | grep "pattern"
6# 好:  grep "pattern" file.txt

第 9 章:整合進其他工作流

與 PowerShell 混用

1# PowerShell cmdlet 的輸出 pipe 給 coreutils
2Get-Process | coreutils sort -k2 -rn
3
4# coreutils 輸出 pipe 給 PowerShell
5ls -la | Select-String "\.log$"
6
7# 注意:PowerShell 的 pipe 傳遞 .NET 物件
8# 而 coreutils 期望文字 stream,混用時注意編碼

與 VS Code 整合

在 VS Code 的 settings.json 中設定終端:

1{
2  "terminal.integrated.defaultProfile.windows": "PowerShell",
3  "terminal.integrated.env.windows": {
4    "PATH": "C:\\Program Files\\coreutils\\cmd;${env:PATH}"
5  }
6}

與 Makefile 搭配

1# Windows + coreutils 可直接使用 UNIX 語法的 Makefile
2SOURCES := $(shell find src/ -name "*.c")
3LOC := $(shell cat $(SOURCES) | wc -l)
4
5clean:
6	find . -name "*.o" -delete
7	rm -rf build/

與 Docker / Container 開發

1# 在 Windows host 上準備檔案、pipe 進 container
2find data/ -name "*.csv" -exec cat {} + | docker run -i python:3 python process.py
3
4# 比較 container 內外的檔案
5diff <(docker exec myapp cat /app/config.yml) config.yml

與 Git 整合

1# 搜尋 Git 歷史中的特定 pattern
2git log --all --oneline | grep "fix" | wc -l
3
4# 清理 untracked 檔案(結合 find)
5find . -name "*.pyc" -not -path "./.git/*" -delete
6
7# 產生變更統計
8git diff --stat | tail -1

第 10 章:重點摘要 Checklist

快速上手

  • 安裝:winget install Microsoft.Coreutils
  • 驗證:coreutils --version 顯示版本
  • 列出指令:coreutils --list
  • 測試基本指令:ls -lagrep --versionfind --version

核心概念

  • 理解 multi-call binary (多重呼叫二進位) 架構
  • 理解 find/sort 的 DOS/GNU 啟發式分流 (heuristic dispatch)
  • 了解 Windows 特有注意事項(CRLF、NUL、路徑分隔符)
  • 知道哪些指令被刻意排除及原因

日常使用

  • 熟練檔案操作:ls, cp, mv, rm, mkdir, touch
  • 熟練文字處理:cat, head, tail, grep, sort, uniq, cut, tr, wc
  • 熟練搜尋:find, xargs, grep -r
  • 熟練 pipeline 組合:|, >, >>, 2>NUL

進階

  • 透過 Registry 設定 find/sort 預設行為
  • 在 PowerShell profile 設定自訂 alias
  • 整合進 CI/CD pipeline
  • 處理 CRLF 換行問題

注意事項

  • PowerShell 7.4+ 才支援(舊版不支援)
  • 安裝需管理員權限,使用不需要
  • Preview 狀態,可能有 breaking changes
  • 建立 symlink 需 Developer Mode 或提權

第 11 章:進一步閱讀

官方資源

上游專案

相關技術

替代方案比較

方案類型優點缺點
microsoft/coreutils原生 binary輕量、快速、DOS 相容Preview、指令子集
WSLLinux 子系統完整 Linux資源開銷、需 Hyper-V
Cygwin相容層最完整安裝大、效能損耗
Git BashMSYS2 子集隨 Git 安裝指令有限
BusyBox-w32原生 binary極小功能受限、無 grep/find
GnuWin32原生 binary穩定老舊、不再維護