跳到主要内容
ansicode
PowerShell

在 PowerShell 中使用 ANSI 转义码 —— $PSStyle、Write-Host、原始 VT

PowerShell 7.2+ 自带 `$PSStyle`,一个带类型的自动变量,可能是所有语言标准库中最现代的颜色 API —— 通过 `$PSStyle.OutputRendering`(`Ansi`/`PlainText`/`Host`)做能力门控,把每个 SGR 码枚举为命名属性(`$PSStyle.Foreground.Red`、`$PSStyle.Bold`、`$PSStyle.Reset`),并与 host 协作,使管道接收的 `Get-ChildItem` 自动去色。PS 5.1(Windows 默认)可退回到 `Write-Host -ForegroundColor`,或用 `` `e `` 转义符(PS 7+)/ `[char]27`(PS 5.1)写原始 VT。Windows 10+ Conhost 与 Windows Terminal 原生解析 ANSI —— 不再需要 `colorama` 类适配。

推荐库

  • $PSStyle (built-in)

    PS 7.2+ 内置的自动变量。命名 SGR 属性(`$PSStyle.Foreground.Red`、`$PSStyle.Bold`、`$PSStyle.Underline`)发出标准转义序列,无需手写 `` `e[31m ``。通过 `$PSStyle.OutputRendering = 'PlainText' | 'Ansi' | 'Host'` 做能力门控 —— 默认 `'Host'` 在管道流向非 TTY 时自动去色。SGR 为主的场景无需第三方库。

  • Write-Host -ForegroundColor

    PS 5.1 兜底 —— 自 2016 以来每个 Windows 版本均可用,无需启用 VT。接受命名 `ConsoleColor` 值(`Red`、`Yellow`、`DarkGray` …),由 host 翻译到当前输出端。代价:`Write-Host` 绕开输出流,彩色文本对 `|`、`>`、transcript 日志与 `4>&1` 重定向均不可见。

  • PSAnsi

    社区模块,把 `$PSStyle` 式的便利反向移植到 PS 5.1,并补充 256 色与真彩色辅助(`Get-Ansi -ForegroundRgb 255,128,0`)—— 内置 `$PSStyle` 只在 7.4+ 通过 `*Rgb` 方法覆盖这块。适合一份脚本同时面向 PS 5.1 与现代 PS 7。

  • oh-my-posh

    跨 shell(PS / Bash / Zsh / Fish / Nu)的提示符引擎 —— 发出带 git 状态、AWS 上下文、kubectl 上下文等的 ANSI 主题提示符。底层是纯 ANSI / OSC;主题由 JSON 驱动,是观察一个抛光的真实 ANSI 提示符在 SGR + OSC 8 超链接 + OSC 133 prompt-mark 表面的样子的好参考。

常用写法

$PSStyle(PS 7.2+)—— 命名 SGR 属性 + Reset
# $PSStyle is an automatic variable — no import, no module install.
# Every named property is a string holding the SGR escape sequence;
# concatenate with text and rely on $PSStyle.Reset to close the run.
# OutputRendering = 'Host' (default) auto-strips when stdout is piped.

if ($PSStyle.OutputRendering -ne 'PlainText') {
  Write-Output "$($PSStyle.Foreground.Red)$($PSStyle.Bold)error:$($PSStyle.Reset) permission denied"
  Write-Output "$($PSStyle.Foreground.Yellow)warn:$($PSStyle.Reset) deprecated flag"
  Write-Output "$($PSStyle.Foreground.BrightGreen)ok:$($PSStyle.Reset) 142 tests passed"
}

# Truecolor (PS 7.4+):
Write-Output "$($PSStyle.Foreground.FromRgb(255,128,0))orange truecolor$($PSStyle.Reset)"

# Capability gate — force-disable in CI / piped contexts you don't trust:
if ($env:NO_COLOR -or -not [Console]::IsOutputRedirected) {
  $PSStyle.OutputRendering = 'Ansi'
} else {
  $PSStyle.OutputRendering = 'PlainText'
}
原始 VT 转义 —— `e[ 转义符(PS 7+)与 [char]27(PS 5.1)
# PS 7+ added the backtick-e escape token, mirroring \e in C strings.
# PS 5.1 (Windows-default) requires the [char]27 numeric-cast form.

# PS 7+ — concise, readable:
Write-Output "`e[1;31mError:`e[0m permission denied"

# PS 5.1 — define once, reuse:
$esc = [char]27
Write-Output "$esc[1;31mError:$esc[0m permission denied"

# Cross-version helper — works on both:
function Esc { param([string]$Body) "$([char]27)[$Body" }
Write-Output "$(Esc '38;2;255;128;0m')orange truecolor$(Esc '0m')"

# Windows note: Conhost on Windows 10 1709+ and Windows Terminal both
# parse VT by default. No SetConsoleMode flip needed unless you target
# Windows 7/8 (and PowerShell 7+ already dropped those).
能力门控 —— IsOutputRedirected + NO_COLOR + WT_SESSION
# The canonical PS colour decision. Stack the same signals as the
# Unix world plus the Windows-specific WT_SESSION hint (Windows Terminal
# sets it; legacy Conhost does not — useful for opting into truecolor).

function Test-AnsiCapable {
  if ($env:NO_COLOR) { return $false }
  if ($env:FORCE_COLOR -and $env:FORCE_COLOR -ne '0') { return $true }
  if ([Console]::IsOutputRedirected) { return $false }
  return $true
}

function Test-TruecolorCapable {
  if (-not (Test-AnsiCapable)) { return $false }
  # Windows Terminal exposes WT_SESSION; supports truecolor since 2019.
  if ($env:WT_SESSION) { return $true }
  # COLORTERM=truecolor|24bit is the de-facto Unix signal — also honoured
  # by VSCode, kitty, alacritty, wezterm, iTerm2, Ghostty under PS.
  return ($env:COLORTERM -in 'truecolor','24bit')
}

if (Test-AnsiCapable) { Write-Output "`e[32mready`e[0m" }
自适应宽度 —— $Host.UI.RawUI.WindowSize.Width
# PS exposes terminal geometry through $Host.UI.RawUI. The Width is the
# column count of the visible window. Use it to size progress bars and
# tables that re-flow on resize — PS doesn't have a built-in resize event,
# so re-query at the top of each render loop.

function Get-Width {
  $w = $Host.UI.RawUI.WindowSize.Width
  if (-not $w -or $w -lt 1) { return 80 }  # piped / detached fallback
  return $w
}

function Render-Bar {
  param([int]$Pct)
  $w = [Math]::Max(10, (Get-Width) - 8)  # 8 for "100% [" + "]"
  $filled = [Math]::Round(($w * $Pct) / 100)
  return "{0,3}% [{1}{2}]" -f $Pct, ('█' * $filled), (' ' * ($w - $filled))
}

Write-Host (Render-Bar 42)
# Re-render on user-initiated tick / progress update — read width again.

相关序列

其他语言