首先,目录结构如下
- 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