作者falcon (falken)
看板Windows
标题[心得] PowerShell 那些恼人的路径 BUG
时间Wed Sep 18 23:54:43 2024
首先,目录结构如下
-
D:\test`[0-2]\test`[0].txt
-
D:\test`[0-2]\test`[1].txt
-
D:\test`[0-2]\test`[2].txt
PowerShell 的 Cmdlet 预设使用
-Path 接受万用字元模式路径,
但 Cmdlet 无法完全正确解读万用字元模式路径中的跳脱处理。
例如,一旦利用跳脱处理来符合目录或档案名称中的特殊字元,
若也使用
*,
?,
[ ] 要符合多种组合,
即使字串模式无误,也找不到任何项目,如下方范例所示。
Get-Item 'D:\test```[0-2`]\test```[[0-2]`].txt'
Get-Item 'D:\test```[0-2`]\test```[*`].txt'
Get-Item 'D:\test```[0-2`]\test```[?`].txt'
以上三个
Get-Item 命令回传都是 null
若要避免此问题,由於路径中其他位置的名称不受此问题影响,
可以先用
Drive:\path\to\dir\* 符合所有子项目的路径,
再用没这问题的
-like 运算子筛选子项目名称。
$items = Get-Item -Path 'D:\test```[0-2`]\*'
$items | Where-Object {$_.Name -like 'test```[[0-2]`].txt'}
$items | Where-Object {$_.Name -like 'test```[*`].txt'}
$items | Where-Object {$_.Name -like 'test```[?`].txt'}
工作目录路径本身带有反引号字元与其他特殊字元时,
PowerShell 无法正确解读相对路径。无论是使用
-LiteralPath 指定路径;
或是使用
-Path 指定万用模式路径,即使做了正确的跳脱处理。
Set-Location -LiteralPath 'D:\test`[0-2]'
Get-Item -Path '*'
0 .. 2 | ForEach-Object {
'test`[' + $_ + '].txt'} | Where-Object {
Test-Path -LiteralPath $_} |
Get-Item -LiteralPath {$_}
以上两个
Get-Item 命令回传都是 null
若要绕过此问题,可以使用完整路径,如下方范例所示。
即根目录开头
Drive:\ 的路径,
例如
C:\Users\UserName\Desktop\MyFile
这样不行
C:Desktop\MyFile
(新版的 PowerShell 已经修复了
-LiteralPath 使用相对路径时问题)
Get-Item -Path 'D:\test```[0-2`]\*'
0 .. 2 | ForEach-Object {
'D:\test`[0-2]\test`[' + $_ + '].txt'} |
Where-Object {Test-Path -LiteralPath $_} |
Get-Item -LiteralPath {$_}
除了相对路径,磁碟机代号也受此问题影响。
(新版的 PowerShell 已经修复了,使用磁碟机代号时,不会遇到此问题)
Set-Location -LiteralPath 'D:\test`[0-2]'
Test-Path -LiteralPath 'D:'
以上
Test-Path 命令回传 False,明显是错误
另外,若在此目录执行外部程式,例如
cmd /c "echo %CD% & pause",
则将意外在新视窗执行,并将
D:\ 视为工作目录。
若要避免此问题,其中一个解决分法如下,改用
Start-Process 执行程式,
并使用
-WorkingDirectory 设定工作目录。
Set-Location -LiteralPath 'D:\test`[0-2]'
Start-Process `
-FilePath 'cmd' `
-ArgumentList '/c "echo %CD% & pause"' `
-WorkingDirectory ($PWD.Path -replace '[`\[\]]', '`$0') `
-Wait `
-NoNewWindow
执行结果如下,正常了
D:\test`[0-2]
Press any key to continue . . .
总结
对於 PowerShell 的 Cmdlet 若要对应任何万元字元模式路径,
也只能递回方法一层一层使用
-like 去比对所有子项目的名称
对於外部程式,使用
Start-Process 就代表不能用
| 符号来通过管线传递资料
不过 Windwos PowerShell 5.1 的管线也暗藏陷阱
PowerShell 把所有经由管线传递的资料都当作字串解码
若要使用影音程式,还是需要
Start-Process 来呼叫 CMD
使用 CMD 的管线功能来避开此问题
PowerShell 虽然功能强大,但一堆反人类设计与 BUG
Windows 的命令壳层也就 CMD 与 PowerSell
用 PowerShell 还是比较容易实现较复杂的操作
虽然反直觉的地方可能改不了
但还是希望微软好好加把劲修 BUG
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 39.12.65.212 (台湾)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/Windows/M.1726674885.A.AA7.html
1F:推 labbat: 直接用c语言写,或者改用python script脚本09/19 02:46
2F:推 smallreader: `````````这麽多颗到底要怎麽看 哦对吼\被拿去当路09/19 03:32
3F:→ smallreader: 径分隔符了 历史共业XD09/19 03:32
从markdown笔记上直接复制过来的
删除了多余语法,改用ptt上色,应该好一些
4F:推 microloft: 用 PS 还得绕过这些 bug 真的是活受罪,我最後都乾脆09/19 13:21
5F:→ microloft: 改用 WSL 或 MSYS2 了09/19 13:21
BUG就看MS什麽时後要修
至於反人类设计,为了相容性只能是历史共业了
MS 的产品还是那个熟悉的味道…
※ 编辑: falcon (27.51.74.66 台湾), 09/19/2024 17:54:53
6F:推 jyhfang: 高手 踩地雷大全 09/20 04:04
7F:→ hunandy14: 其实真实的情况是 pwsh 社群决议改掉预设万用了 09/27 12:11
8F:→ hunandy14: 他不是bug就是当初设计 不符合直觉 09/27 12:12
9F:→ hunandy14: 所以应该不会修了,那是式样不是bug 09/27 12:12
10F:推 hunandy14: 测试结果确实没有bug存在,只是恼人的设计 09/27 13:02
12F:→ hunandy14: 第二个问题管道传送是字符而不是二进制 09/27 13:09
13F:→ hunandy14: 这个就也是为了方便性牺牲掉的设计 09/27 13:09
15F:→ hunandy14: 趁早换了pwsh至少有社群帮你扛着改掉这些白痴设计 09/27 13:15
※ 编辑: falcon (110.28.1.89 台湾), 09/28/2024 07:42:36