mcpField
P
powershell-shell-detection

powershell-shell-detection

github.com/josiahsiegel开发59207 次安装19 周前更新
代码仓库

关于 powershell-shell-detection

面向 Windows 脚本开发者的跨 Shell 检测与兼容指南,重点介绍 PowerShell、Git Bash/MSYS2 和 WSL 的识别及差异。内容包括路径处理、环境变量、命令和自动路径转换问题。

主要功能

  1. 01检测 PowerShell、Git Bash 与 WSL
  2. 02比较 Shell 环境变量和路径
  3. 03说明 Git Bash 自动路径转换
  4. 04编写适配 Shell 的脚本
  5. 05排查命令与路径兼容问题

适用场景

  1. 01让脚本识别当前 Shell
  2. 02处理 Windows 与 Bash 路径差异
  3. 03修复命令参数被自动转换
  4. 04排查跨 Shell 命令不可用

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/josiahsiegel/claude-plugin-marketplace --skill powershell-shell-detection

安装后在 Claude Code 中输入/powershell-shell-detection确认已加载。

详细介绍

PowerShell Shell 检测与跨 Shell 兼容性

在 Windows 上区分 PowerShell 与 Git Bash/MSYS2 Shell 的重要指南,涵盖 Shell 专属的路径处理方式和兼容性说明。

Shell 检测优先级(Windows)

在 Windows 上工作时,正确识别 Shell 环境对于妥善处理路径和执行命令至关重要。

检测顺序(从最可靠到最不可靠)
  1. process.env.PSModulePath(PowerShell 专用)
  2. process.env.MSYSTEM(Git Bash/MinGW 专用)
  3. process.env.WSL_DISTRO_NAME(WSL 专用)
  4. uname -s 输出(跨 Shell,需要执行命令)

PowerShell 检测

主要指标

PSModulePath(最可靠):

# PowerShell detection
if ($env:PSModulePath) {
    Write-Host "Running in PowerShell"
    # PSModulePath contains 3+ paths separated by semicolons
    $env:PSModulePath -split ';'
}

# Check PowerShell version
$PSVersionTable.PSVersion
# Output: 7.5.4 (PowerShell 7) or 5.1.x (Windows PowerShell)

PowerShell 专属变量:

# These only exist in PowerShell
$PSVersionTable    # Version info
$PSScriptRoot      # Script directory
$PSCommandPath     # Script full path
$IsWindows         # Platform detection (PS 7+)
$IsLinux           # Platform detection (PS 7+)
$IsMacOS           # Platform detection (PS 7+)
脚本中的 Shell 类型检测
function Get-ShellType {
    if ($PSVersionTable) {
        return "PowerShell $($PSVersionTable.PSVersion)"
    }
    elseif ($env:PSModulePath -and ($env:PSModulePath -split ';').Count -ge 3) {
        return "PowerShell (detected via PSModulePath)"
    }
    else {
        return "Not PowerShell"
    }
}

Get-ShellType

Git Bash / MSYS2 检测

主要指标

MSYSTEM 环境变量(最可靠):

# Bash detection in Git Bash/MSYS2
if [ -n "$MSYSTEM" ]; then
    echo "Running in Git Bash/MSYS2: $MSYSTEM"
fi

# MSYSTEM values:
# MINGW64 - Native Windows 64-bit environment
# MINGW32 - Native Windows 32-bit environment
# MSYS    - POSIX-compliant build environment

次要检测方法:

# Using OSTYPE (Bash-specific)
case "$OSTYPE" in
    msys*)   echo "MSYS/Git Bash" ;;
    cygwin*) echo "Cygwin" ;;
    linux*)  echo "Linux" ;;
    darwin*) echo "macOS" ;;
esac

# Using uname (Most portable)
case "$(uname -s)" in
    MINGW64*) echo "Git Bash 64-bit" ;;
    MINGW32*) echo "Git Bash 32-bit" ;;
    MSYS*)    echo "MSYS" ;;
    CYGWIN*)  echo "Cygwin" ;;
    Linux*)   echo "Linux" ;;
    Darwin*)  echo "macOS" ;;
esac

Windows 上的跨 Shell 兼容性

关键差异
方面PowerShellGit Bash/MSYS2
环境变量$env:VARIABLE$VARIABLE
路径分隔符;(分号):(冒号)
路径格式C:\Windows\System32/c/Windows/System32
主目录$env:USERPROFILE$HOME
临时目录$env:TEMP/tmp
命令格式Get-ChildItemls(原生命令)
别名PowerShell cmdlet 别名Unix 命令别名
路径处理:PowerShell 与 Git Bash

PowerShell 路径处理:

# Native Windows paths work directly
$path = "C:\Users\John\Documents"
Test-Path $path  # True

# Forward slashes also work in PowerShell 7+
$path = "C:/Users/John/Documents"
Test-Path $path  # True

# Use Join-Path for cross-platform compatibility
$configPath = Join-Path -Path $PSScriptRoot -ChildPath "config.json"

# Use [System.IO.Path] for advanced scenarios
$fullPath = [System.IO.Path]::Combine($home, "documents", "file.txt")

Git Bash 路径处理:

# Git Bash uses Unix-style paths
path="/c/Users/John/Documents"
test -d "$path" && echo "Directory exists"

# Automatic path conversion (CAUTION)
# Git Bash converts Unix-style paths to Windows-style
# /c/Users → C:\Users (automatic)
# Arguments starting with / may be converted unexpectedly

# Use cygpath for manual conversion
cygpath -u "C:\path"      # → /c/path (Unix format)
cygpath -w "/c/path"      # → C:\path (Windows format)
cygpath -m "/c/path"      # → C:/path (Mixed format)

Git Bash 中的自动路径转换(重要)

Git Bash/MSYS2 会在某些情况下自动转换路径,这可能导致问题:

触发转换的情况
# Leading forward slash triggers conversion
command /foo         # Converts to C:\msys64\foo

# Path lists with colons
export PATH=/foo:/bar  # Converts to C:\msys64\foo;C:\msys64\bar

# Arguments after dashes
command --path=/foo    # Converts to --path=C:\msys64\foo
不会触发转换的情况
# Arguments with equals sign (variable assignments)
VAR=/foo command      # NOT converted

# Drive specifiers
command C:/path       # NOT converted

# Arguments with semicolons (already Windows format)
command "C:\foo;D:\bar"  # NOT converted

# Double slashes (Windows switches)
command //e //s       # NOT converted
禁用路径转换
# Disable ALL conversion (Git Bash)
export MSYS_NO_PATHCONV=1
command /foo  # Stays as /foo

# Exclude specific patterns (MSYS2)
export MSYS2_ARG_CONV_EXCL="*"           # Exclude everything
export MSYS2_ARG_CONV_EXCL="--dir=;/test"  # Specific prefixes

在 Windows 上何时使用 PowerShell 或 Git Bash

以下情况使用 PowerShell:
  • ✅ Windows 专属任务 — 注册表、WMI、Windows 服务
  • ✅ Azure/Microsoft 365 自动化 — Az、Microsoft.Graph 模块
  • ✅ 模块生态系统 — 使用 PSGallery 模块
  • ✅ 面向对象的管道 — 丰富的对象操作功能
  • ✅ 原生 Windows 集成 — 内置于 Windows
  • ✅ 使用 pwsh 的 CI/CD — GitHub Actions、Azure DevOps
  • ✅ 跨平台脚本编写 — PowerShell 7 可在 Linux/macOS 上运行

PowerShell 场景示例:

# Azure VM management with Az module
Connect-AzAccount
Get-AzVM -ResourceGroupName "Production" |
    Where-Object {$_.PowerState -eq "VM running"} |
    Stop-AzVM -Force
以下情况使用 Git Bash:
  • ✅ 兼容 Unix 工具 — sed、awk、grep、find
  • ✅ Git 操作 — 原生 Git 命令行体验
  • ✅ 执行 POSIX 脚本 — 运行 Linux Shell 脚本
  • ✅ 跨平台 Shell 脚本 — 来自 Linux/macOS 的 Bash 脚本
  • ✅ 文本处理 — Unix 文本工具(sed、awk、cut)
  • ✅ 开发工作流 — 使用 Unix 工具的 Node.js、Python、Ruby

Git Bash 场景示例:

# Git workflow with Unix tools
git log --oneline | grep -i "feature" | awk '{print $1}' |
    xargs git show --stat

Shell 感知型脚本设计

检测并适配(PowerShell)
# Detect if running in PowerShell or Git Bash context
function Test-PowerShellContext {
    return ($null -ne $PSVersionTable)
}

# Adapt path handling based on context
function Get-CrossPlatformPath {
    param([string]$Path)

    if (Test-PowerShellContext) {
        # PowerShell: Use Join-Path
        return (Resolve-Path $Path -ErrorAction SilentlyContinue).Path
    }
    else {
        # Non-PowerShell context
        Write-Warning "Not running in PowerShell. Path operations may differ."
        return $Path
    }
}
检测并适配(Bash)
# Detect shell environment
detect_shell() {
    if [ -n "$MSYSTEM" ]; then
        echo "git-bash"
    elif [ -n "$PSModulePath" ]; then
        echo "powershell"
    elif [ -n "$WSL_DISTRO_NAME" ]; then
        echo "wsl"
    else
        echo "unix"
    fi
}

# Adapt path handling
convert_path() {
    local path="$1"
    local shell_type=$(detect_shell)

    case "$shell_type" in
        git-bash)
            # Convert Windows path to Unix style
            echo "$path" | sed 's|\\|/|g' | sed 's|^\([A-Z]\):|/\L\1|'
            ;;
        *)
            echo "$path"
            ;;
    esac
}

# Usage
shell_type=$(detect_shell)
echo "Running in: $shell_type"

环境变量对照

常见环境变量
变量PowerShellGit Bash用途
用户名$env:USERNAME$USER当前用户
主目录$env:USERPROFILE$HOME用户主目录
临时目录$env:TEMP/tmp临时文件
路径列表$env:Path(; 分隔)$PATH(: 分隔)可执行文件路径
Shell 检测$env:PSModulePath$MSYSTEMShell 标识符
跨 Shell 访问变量

PowerShell 访问环境变量:

$env:PATH              # Current PATH
$env:PSModulePath      # PowerShell module paths
$env:MSYSTEM           # Would be empty in PowerShell
[Environment]::GetEnvironmentVariable("PATH", "Machine")  # System PATH

Git Bash 访问环境变量:

echo $PATH             # Current PATH
echo $MSYSTEM          # Git Bash: MINGW64, MINGW32, or MSYS
echo $PSModulePath     # Would be empty in pure Bash

实用示例

示例 1:跨 Shell 查找文件

PowerShell:

# Find files modified in last 7 days
Get-ChildItem -Path "C:\Projects" -Recurse -File |
    Where-Object { $_.LastWriteTime -gt (Get-Date).AddDays(-7) } |
    Select-Object FullName, LastWriteTime

Git Bash:

# Same operation in Git Bash
find /c/Projects -type f -mtime -7 -exec ls -lh {} \;
示例 2:进程管理

PowerShell:

# Stop all Chrome processes
Get-Process chrome -ErrorAction SilentlyContinue | Stop-Process -Force

Git Bash:

# Same operation in Git Bash
ps aux | grep chrome | awk '{print $2}' | xargs kill -9 2>/dev/null
示例 3:文本文件处理

PowerShell:

# Extract unique email addresses from logs
Get-Content "logs.txt" |
    Select-String -Pattern '\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b' |
    ForEach-Object { $_.Matches.Value } |
    Sort-Object -Unique

Git Bash:

# Same operation in Git Bash
grep -oE '\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b' logs.txt |
    sort -u

跨 Shell 问题排查

问题 1:找不到命令

问题: 命令在一个 Shell 中可以运行,在另一个 Shell 中却不行

# PowerShell
Get-Process  # Works
# Git Bash
Get-Process  # Command not found

解决方案: 请注意,PowerShell cmdlet 在 Bash 中不可用。在 Git Bash 中使用原生命令,或安装 PowerShell Core(pwsh):

# Run PowerShell from Git Bash
pwsh -Command "Get-Process"
问题 2:路径格式不匹配

问题: 路径无法在不同 Shell 之间通用

# Git Bash path
/c/Users/John/file.txt  # Works in Bash

# PowerShell
Test-Path "/c/Users/John/file.txt"  # May fail

解决方案: 使用 cygpath 转换,或规范化路径:

# Convert to Windows format for PowerShell
win_path=$(cygpath -w "/c/Users/John/file.txt")
pwsh -Command "Test-Path '$win_path'"
问题 3:别名冲突

问题: ls、cd、cat 的行为各不相同

# PowerShell
ls  # Actually runs Get-ChildItem
# Git Bash
ls  # Runs native Unix ls command

解决方案: 在 PowerShell 脚本中使用完整的 cmdlet 名称:

# Instead of: ls
Get-ChildItem  # Explicit cmdlet name

最佳实践摘要

PowerShell 脚本
  1. ✅ 使用 $PSScriptRoot 获取相对于脚本的路径
  2. ✅ 使用 Join-Path 或 [IO.Path]::Combine() 处理路径
  3. ✅ 避免硬编码反斜杠
  4. ✅ 使用完整的 cmdlet 名称(不使用别名)
  5. ✅ 在所有目标平台上进行测试
  6. ✅ 使用 $IsWindows、$IsLinux、$IsMacOS 检测平台
Git Bash 脚本
  1. ✅ 检查 $MSYSTEM 以检测 Git Bash
  2. ✅ 需要时使用 cygpath 转换路径
  3. ✅ 需要时设置 MSYS_NO_PATHCONV=1 以禁用自动转换
  4. ✅ 为包含空格的路径加上引号
  5. ✅ 在 Bash 中使用 Unix 风格路径(/c/...)
  6. ✅ 调用 Windows 工具时转换为 Windows 路径
跨 Shell 开发
  1. ✅ 说明脚本所需的 Shell
  2. ✅ 在脚本开头添加 Shell 检测
  3. ✅ 针对错误的 Shell 提供清晰的错误消息
  4. ✅ 考虑创建包装脚本以实现跨 Shell 兼容性
  5. ✅ 如果同时支持 PowerShell 和 Git Bash,请在两者中进行测试

资源


最后更新: 2025 年 10 月

评论

支持 Markdown