Re: [心得] PowerShell 那些惱人的路徑 BUG
: hunandy14: 其實真實的情況是 pwsh 社群決議改掉預設萬用了
: hunandy14: 他不是bug就是當初設計 不符合直覺
: hunandy14: 所以應該不會修了,那是式樣不是bug
: hunandy14: 測試結果確實沒有bug存在,只是惱人的設計
bug 是指對於萬元字元路徑的跳脫處理有誤
預設萬元字元我只當它是反人類設計而已
https://github.com/PowerShell/PowerShell/issues/7999
主要是講這 bug 的影響
順便提了兩句微軟的雞婆的
設計導致多餘的困擾,不是本篇的重點
由於 -like 運算子跟 cmdlet 的路徑參數
對於萬用字元的解讀不同
這兩者都是 PowerShell 原生的功能
對於同樣的東西應該有相同行為
所以說,在這問題上最多只能有一方是正確的
https://i.imgur.com/YiXffzL.png
如過這是特性不是 bug 的話
那工作目錄中的特殊字元應該要做獨特的跳脫處理
畢竟這是在 cmdlet 內部處理的
不應該發生錯誤
Set-Location -LiteralPath 'D:\test`[0-2]'
Resolve-Path -Path .
Resolve-Path -LiteralPath .
使用 -Path . 與使用 -LiteralPath .
前者在任何版本都會發生錯誤
則只有在新的跨平台版 PS 才能得到正確路徑
https://i.imgur.com/m5uoXdF.png
另外,我不是說管線那設計是 bug
bug 是指在這個工作目錄把程式作為命令執行
會因為因為工作目錄路徑導致異常行為
https://i.imgur.com/mbG9jTo.png
Start-Process 有 -WorkingDirectory 可以用
它會直接拿你跳脫處理過的路徑當 base 去組出完整路徑
就能避開對於工作目錄路徑本身包含 ` 時的問題
而 System.Diagnostics.Process 不是 PS 的 cmdlet 所以沒此問題
拿 Start-Process 舉例,只因為它是 PowerShell 的 Cmdlet
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 110.28.1.89 (臺灣)
※ 文章網址: https://www.ptt.cc/bbs/Windows/M.1727480822.A.7BF.html
※ 編輯: falcon (110.28.1.89 臺灣), 09/28/2024 09:15:36
→
09/28 23:00,
1月前
, 1F
09/28 23:00, 1F
→
09/28 23:01,
1月前
, 2F
09/28 23:01, 2F
→
09/28 23:03,
1月前
, 3F
09/28 23:03, 3F
→
09/28 23:05,
1月前
, 4F
09/28 23:05, 4F
→
09/28 23:07,
1月前
, 5F
09/28 23:07, 5F
→
09/28 23:08,
1月前
, 6F
09/28 23:08, 6F
→
09/28 23:10,
1月前
, 7F
09/28 23:10, 7F
→
09/28 23:11,
1月前
, 8F
09/28 23:11, 8F
→
09/28 23:13,
1月前
, 9F
09/28 23:13, 9F
如果邏輯一致就能說是語言特性
要 user 吞下去就算了
但 PowerShell 自己內部處理都搞不定實在太蠢了
下圖是我自己實作以比對名稱的方式遞迴搜尋路徑
https://i.imgur.com/ZK32zgK.png
這樣的結果才是我想要的
可以直接用管道餵路徑其他 cmdlet 如 get-item
※ 編輯: falcon (110.28.1.89 臺灣), 09/29/2024 00:05:02
→
09/29 00:09,
1月前
, 10F
09/29 00:09, 10F
→
09/29 00:34,
1月前
, 11F
09/29 00:34, 11F
→
09/29 00:40,
1月前
, 12F
09/29 00:40, 12F
→
09/29 00:42,
1月前
, 13F
09/29 00:42, 13F
→
09/29 12:02,
1月前
, 14F
09/29 12:02, 14F
→
09/29 12:03,
1月前
, 15F
09/29 12:03, 15F
→
09/29 12:04,
1月前
, 16F
09/29 12:04, 16F
→
09/29 12:06,
1月前
, 17F
09/29 12:06, 17F
→
09/29 12:08,
1月前
, 18F
09/29 12:08, 18F
→
09/29 13:36,
1月前
, 19F
09/29 13:36, 19F
我覺得就只是最初開發者的低級失誤
可能 user 用多了,改不了而已
→
09/29 14:07,
1月前
, 20F
09/29 14:07, 20F
→
09/29 14:11,
1月前
, 21F
09/29 14:11, 21F
GetFullPath() 不適用於所有 PSDrive 的路徑
例如 HKLM:\
所以我才需要自己寫模組
用於所有 Get-ltem 的使用場景
話說回來 萬用字元
原來就只是要重複做跳脫而已
$literal = 'te`st`[1].txt'
$pattern = $literal -replace '[`\*\?\[\]]', '`$0'
if ($literal -match '[`\*\?\[\]]') {
$pattern = $pattern -replace '[`\*\?\[\]]', '`$0'
}
PowerShell 的萬用字元底層應該是正規表示法
這是轉換失誤的BUG吧,用久了就變語言特性了
就我的理解應該要像下面這麼做
$wildcardPattern | Select-String -Pattern '`?.' -AllMatches |
ForEach-Object { $_.Matches } | ForEach-Object { $_.Value } |
ForEach-Object {
if ($_ -match '`([\[\]])') { '\' + $Matches[1] }
elseif ($_ -match '`(.)') { [regex]::escape($Matches[1]) }
elseif ($_ -match '\*') { '.*' }
elseif ($_ -match '\?') { '.' }
elseif ($_ -match '[\[\]]') { $Matches[0] }
else { [regex]::escape($_) }
} | Set-Variable regexPatternParts
$regexPattern = $regexPatternParts -join ''
而跳脫處理只需要下面這樣
$wildcardPattern = $literal -replace '[`\*\?\[\]]', '`$0'
※ 編輯: falcon (110.28.1.89 臺灣), 09/29/2024 15:02:46
→
09/29 15:06,
1月前
, 22F
09/29 15:06, 22F
→
09/29 15:06,
1月前
, 23F
09/29 15:06, 23F
→
09/29 15:07,
1月前
, 24F
09/29 15:07, 24F
→
09/29 15:16,
1月前
, 25F
09/29 15:16, 25F
※ 編輯: falcon (110.28.1.89 臺灣), 09/29/2024 15:21:06
→
09/29 17:21,
1月前
, 26F
09/29 17:21, 26F
→
09/29 17:21,
1月前
, 27F
09/29 17:21, 27F
→
09/29 17:21,
1月前
, 28F
09/29 17:21, 28F
※ 編輯: falcon (110.28.1.89 臺灣), 09/30/2024 15:27:01
→
10/09 14:23,
1月前
, 29F
10/09 14:23, 29F
→
10/09 14:24,
1月前
, 30F
10/09 14:24, 30F
→
10/09 14:27,
1月前
, 31F
10/09 14:27, 31F
→
10/09 15:07,
1月前
, 32F
10/09 15:07, 32F
→
10/09 18:04,
1月前
, 33F
10/09 18:04, 33F
→
10/09 18:04,
1月前
, 34F
10/09 18:04, 34F
→
10/09 18:04,
1月前
, 35F
10/09 18:04, 35F
→
10/09 18:04,
1月前
, 36F
10/09 18:04, 36F
→
10/09 18:08,
1月前
, 37F
10/09 18:08, 37F
→
10/09 18:32,
1月前
, 38F
10/09 18:32, 38F
我有一個想法是用同名的 function 去代替 cmdlet
例如下面這樣
function Get-Item {
$newArgs = $args
# 在此修改 $newargs
# 找出單獨的字串或 -Path, -LiteralPath 參數的引數
# 將其作為路徑擴展為根目錄 ("PSDrive:\") 開頭的完整的路徑
Microsoft.PowerShell.Management\Get-Item @newArgs
}
但不知道 cmdlet 是如何從 $args 中區分字串與參數名稱
由於引號被去掉了,取值也一樣
用 .GetType() 列出類型也都一樣
看起來也不是依照先後順序與開頭字元為準
https://i.imgur.com/uFynvgK.png
※ 編輯: falcon (39.9.131.112 臺灣), 10/09/2024 22:09:05
※ 編輯: falcon (39.9.131.112 臺灣), 10/09/2024 22:10:30
→
10/09 23:04,
1月前
, 39F
10/09 23:04, 39F
→
10/09 23:04,
1月前
, 40F
10/09 23:04, 40F
→
10/09 23:05,
1月前
, 41F
10/09 23:05, 41F
→
10/09 23:11,
1月前
, 42F
10/09 23:11, 42F
討論串 (同標題文章)
完整討論串 (本文為第 2 之 3 篇):
Windows 近期熱門文章
PTT數位生活區 即時熱門文章