Cmd powershell pitfalls
Skill High-cla/multi-skilled-repository/skills/cmd-powershell-pitfalls
Windows CMD 和 PowerShell 错误排查与陷阱规避指南,含跨平台差异和修复模式From its SKILL.md
npx -y skills add High-cla/multi-skilled-repository --skill cmd-powershell-pitfallsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
8.1 KB, ~3.1k tokens by cl100k_base, as published. Nobody here has run it
CMD + PowerShell 混合脚本避坑指南
1. 编码 (Code Page)
chcp 65001 破坏变量展开
@echo off
chcp 65001 >nul
set "VAR=中文路径"
echo %VAR% REM 可能输出乱码或空 — 65001 下 cmd 解析异常
规则:
chcp 65001后 cmd 对%VAR%的解析在某些 Windows 版本有 bug,尤其是路径含中文时- 修复:不在 cmd 中用中文注释/输出,改用英文;或保持默认 936 (GBK)
- 最佳实践:批处理脚本避免中文字符,使用英文
2. for 循环体中的括号 )
for 的 () 体用 ) 关闭。如果命令本身含 ),必须用 ^ 转义。
REM 错误
for %%f in (*.lua) do (
echo addappid(%%a, 1) REM 这里的 ) 被当作 for 体结束
)
REM 正确
for %%f in (*.lua) do (
echo addappid(%%a, 1^) REM ^) 将 ) 转义为字面字符
)
规则: for 循环体内任何 ) 都必须写作 ^)。
3. 括号引起的重定向顺序问题
同第 2 条,() 体内的重定向需注意 ) 被截断。
4. %~dp0 路径处理
cd /d "%~dp0" REM 进入脚本所在目录(含末尾 \)
规则:
%~dp0返回值含尾部\(如C:\dir\)- 拼接文件时不需要额外加
\:"%~dp0file.lua"
~ 修饰符速查
| 语法 | 含义 | 示例 |
|---|---|---|
%~dp0 | 盘符+路径 | C:\tools\ |
%~f0 | 完整路径 | C:\tools\script.cmd |
%~n0 | 文件名(无扩展名) | script |
%~x0 | 扩展名 | .cmd |
5. cmd 行续 ^ 的引用限制
^ 续行只在引号外生效。
REM 错误:^ 在 "" 内部是字面字符
powershell -Command "Write-Host 'hello' ^
'world'"
REM 正确
powershell -Command ^
"$a=1;" ^
"$b=2;" ^
"Write-Host ($a+$b)"
6. PowerShell 嵌入 cmd 的引号逃逸
cmd 的 "..." 内不支持 \" 作为转义。
REM 错误
powershell -Command "Write-Host \"hello\""
REM 正确:用单引号
powershell -Command "Write-Host 'hello'"
7. Get-Location 返回 PathInfo 非字符串
$d = Get-Location # PathInfo 对象
$d + "\file.lua" # 错误
$d.Path + "\file.lua" # 正确
8. cmd 中 $ 与 % 传递给 PowerShell
| 在 cmd 中写 | 传递给 PowerShell |
|---|---|
$_ | 当前管道对象 ($_) |
$var | PowerShell 变量 |
%VAR% | cmd 展开环境变量(先于 PS 执行) |
%%f (for 内) | for 循环变量 |
9. if /i not 字符串比较
if /i not "%%f"=="file.lua" (
REM 大小写不敏感比较
)
注意 == 前后不能加空格。
10. findstr 正则过滤
dir /b *.lua | findstr /r "^[0-9][0-9]*\.lua$"
findstr 局限: 不支持 \d、+、?、{n,m},不支持非贪婪。
11. 管道 | 在 cmd 字符串中
REM 正确:| 在 "..." 内不会被 cmd 当作管道
powershell -Command "Get-ChildItem | Where-Object { $_.Length -gt 1kb }"
12. 延迟变量扩展 (Delayed Expansion)
setlocal enabledelayedexpansion
set "count=0"
for %%f in (*.lua) do (
set /a count+=1
echo !count!: %%f
)
endlocal
规则: for/if 内修改并读取变量必须用 !var!。
13. Set-Content 编码陷阱
# Windows PowerShell (<= 5.1):默认 UTF-8 With BOM
Set-Content path "text" # UTF-8 + BOM
Set-Content path "text" -Encoding ASCII # ASCII(无BOM)
# PowerShell 7+:默认 UTF-8 No BOM
Set-Content path "text" # UTF-8 No BOM
14. 错误处理
some_command
if %ERRORLEVEL% neq 0 (
echo Failed with code %ERRORLEVEL%
exit /b %ERRORLEVEL%
)
规则: cmd 用 %ERRORLEVEL%,PowerShell 用 $LASTEXITCODE。
15. 逐 >> 追加 vs 一次性重定向
REM 快:整个 for 输出一次重定向
(
for %%f in (*.lua) do echo %%f
) > out.txt
16. .NET API 加速 PowerShell
| 慢 (cmdlet) | 快 (.NET 直调) |
|---|---|
Get-ChildItem *.lua | [IO.Directory]::GetFiles($dir, '*.lua') |
Get-Content file.txt | [IO.File]::ReadAllLines($path) |
Set-Content path txt | [IO.File]::WriteAllText($path, $text) |
17. 退出码检测
powershell -NoProfile -Command "...; exit $LASTEXITCODE"
if %ERRORLEVEL% neq 0 echo PowerShell failed
18. @echo off 位置
REM 正确:第一行就是 @echo off
@echo off
echo starting...
19. PowerShell 执行策略绕过
powershell -ExecutionPolicy Bypass -File script.ps1
20. 特殊字符转义表
| 字符 | cmd 转义 | PowerShell 转义 |
|---|---|---|
^ | ^^ | `^ |
& | ^& | `& |
| | ^| | `| |
</> | ^</^> | `</`> |
" | \" (无效) | 用单引号替代 |
$ | $$ | `$ |
% | %% | `% |
21. 路径含空格的处理
set "path=C:\Program Files\app"
cd "%path%"
22. 环境变量作用域
| 级别 | cmd | PowerShell |
|---|---|---|
| 当前进程 | set VAR=val | $env:VAR = "val" |
| 用户永久 | setx VAR val | [Environment]::SetEnvironmentVariable("VAR","val","User") |
| 系统永久 | setx VAR val /M | [Environment]::SetEnvironmentVariable("VAR","val","Machine") |
23. 数组与集合
复杂数据结构优先用 PowerShell,cmd 只负责调用。
24. 正则表达式差异
复杂正则用 PowerShell (Select-String),简单过滤用 findstr。
25. 多行字符串
$sql = @"
SELECT *
FROM users
WHERE id=1
"@
26. 后台执行
start /min powershell -WindowStyle Hidden -Command "..."
27. Unicode 与 BOM
写文件时用 UTF8Encoding($false) 创建无 BOM 的 UTF-8。
28. 管道编码传递
cmd 管道默认 ANSI (GBK),PowerShell 默认 UTF-8。跨管道传中文时优先让 PowerShell 全程处理。
29. 临时文件竞争条件
并发场景下必须用唯一标识 (GUID/PID/时间戳)。
30. 权限提升检测
net session >nul 2>&1
if %ERRORLEVEL% neq 0 (
powershell -Command "Start-Process cmd -ArgumentList '/c','%~f0' -Verb RunAs"
exit /b
)
31. 长路径支持 (>260 字符)
Windows 10 1607+ 启用长路径支持或使用 \\?\ 前缀。
32. 超时与中断
长时间运行命令必须设置超时机制。
$p=[Diagnostics.Process]::Start('cmd','/c command'); if(!$p.WaitForExit(5000)){ $p.Kill(); exit 1 }
33. 日志记录
所有生产脚本必须记录带时间戳的操作日志。
34. 返回值标准化
使用标准化的退出码便于调用方判断错误类型。
35. 配置文件读取
复杂配置用 JSON/YAML,通过 PowerShell 解析;简单配置用环境变量。
Git Bash 与 MSYS2 路径转换
Git Bash 的 MSYS2 层自动将 / 开头的参数(如 /PID)转换为 Windows 路径,导致传给 powershell.exe 的参数被破坏。
| 问题 | 表现 | 修复 |
|---|---|---|
/PID -> 路径 | spawnSync powershell.exe ETIMEDOUT | 设 MSYS2_ARG_CONV_EXCL=* |
| 路径参数丢失 | 传参失败 | 用 // 前缀绕过转换 |
重复安装
opencode 同时通过 npm 和 WinGet 安装时,PATH 顺序决定生效版本。当前仅保留 npm 版。
检查清单
-
)在for体内是否用^)转义 -
"..."内无\"(用单引号替代) -
Get-Location是否调用了.Path -
chcp 65001后无中文/特殊字符变量 -
for内修改变量是否用了延迟展开!var! -
Set-Content指定了正确编码 -
%~dp0路径拼接无多余\ -
.ps1执行策略用-ExecutionPolicy Bypass -
@echo off是否为第一行 - 路径含空格时是否用引号包裹
- 特殊字符是否按层级正确转义
- 输出文件是否确认无 BOM 问题
- 管道传递中文时是否统一编码
- 需要管理员权限时是否先检测
- 长路径是否启用支持或使用
\\?\前缀 - 长时间命令是否设置超时
- 退出码是否标准化
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.