作者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/m.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