[心得] PowerShell 那些惱人的路徑 BUG
首先,目錄結構如下
- 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://www.ptt.cc/bbs/Windows/M.1726674885.A.AA7.html
推
09/19 02:46,
2月前
, 1F
09/19 02:46, 1F
推
09/19 03:32,
2月前
, 2F
09/19 03:32, 2F
→
09/19 03:32,
2月前
, 3F
09/19 03:32, 3F
從markdown筆記上直接複製過來的
刪除了多餘語法,改用ptt上色,應該好一些
推
09/19 13:21,
2月前
, 4F
09/19 13:21, 4F
→
09/19 13:21,
2月前
, 5F
09/19 13:21, 5F
BUG就看MS什麼時後要修
至於反人類設計,為了相容性只能是歷史共業了
MS 的產品還是那個熟悉的味道…
※ 編輯: falcon (27.51.74.66 臺灣), 09/19/2024 17:54:53
推
09/20 04:04,
2月前
, 6F
09/20 04:04, 6F
→
09/27 12:11,
1月前
, 7F
09/27 12:11, 7F
→
09/27 12:12,
1月前
, 8F
09/27 12:12, 8F
→
09/27 12:12,
1月前
, 9F
09/27 12:12, 9F
推
09/27 13:02,
1月前
, 10F
09/27 13:02, 10F
→
09/27 13:05,
1月前
, 11F
09/27 13:05, 11F
→
09/27 13:09,
1月前
, 12F
09/27 13:09, 12F
→
09/27 13:09,
1月前
, 13F
09/27 13:09, 13F
→
09/27 13:11,
1月前
, 14F
09/27 13:11, 14F
→
09/27 13:15,
1月前
, 15F
09/27 13:15, 15F
※ 編輯: falcon (110.28.1.89 臺灣), 09/28/2024 07:42:36
討論串 (同標題文章)
完整討論串 (本文為第 1 之 3 篇):
Windows 近期熱門文章
PTT數位生活區 即時熱門文章