PowerShell 可以無縫整合 .NET 程式,威力無窮。但這也導致很多時候我搞不清楚這裡可以直接用 C# 寫法,還是該照 PowerShell 的規矩來?

新手上路階段,我最常踩到的坑就是多參數 PowerShell 函式的寫法。例如下面這段程式,大家猜猜輸出的結果是什麼? Hell?

function Mid([string]$str, [int]$pos, [int]$len) {
    return $str.Substring($pos, $len);
}
$input = "Hello, World!"
Write-Host Mid($input, 0, 4)

錯! 「Mid Hello, World 0 4」是什麼鬼啦?What the hell.

拆解問題,第一個錯是 Write-Host Mid($input, 0 , 4) 並不是你所想的先執行 Mid($input, 0, 4) 再將結果印出來,而是被解讀成「印出"Mid",再印出陣列($input, 0, 4)」,若要印出 Mid($input,0,4),應寫成 Write-Host "$(Mid($input, 0, 4))":

好了,不再出現奇怪結果,而是沒有結果。XD Mid($input, 0, 4) 什麼都沒傳回,我在程式後方加了一段將結果存入 $result 印出,印證結果為空字串。

Mid 是一個 PowerShell 函式,呼叫時傳入參數寫法跟 C# 有很最大不同,參數應使用空白分隔而非逗號,另外,PowerShell 中 (p1, p2, p3) 被解讀成陣列,而呼叫函式時不需要用括號包住參數,這點跟 C# 很不相同。因此,我們心中以為的 Mid($input, 0, 4),在 PowerShell 中其實應寫成 Mid $input 0 4:

這樣就對了!

除了 Mid $input 0 4,我們也可以用具名參數寫法,不管順序,還可選擇性傳入少數參數。所以,寫成 Mid -pos 0 -len 4 -str $input 會得到同樣結果,而 Mid -len 5 -str $input 則會得到 Hello (未指定 $pos,預設 0):

最後,來看看為什麼 Mid($input, 0, 4) 會傳回空白?

謎團揭曉! 因為我們宣告 $str 的型別為字串,當寫成 Mid($input, 0, 4),被解讀為傳入一個三元素陣列到第一個參數 $str,因 $str 必須為字串,PowerShell 將其陣列轉型為字串,以空白串接三個元素變成 "Hello, Wolrd! 0 4",而 $pos = 0、$len = 0,故傳回空字串。如果我們不宣告 $str 為 [string],則會出現不同結果:

由測試結果可知,$str 未指定型別時會得到 System.Object[],Write-Host "`$str=$str" 時強轉成字串結果與上個實驗相同,但後續再呼叫 .SubString() 就會因型別不符噴出莫名其妙錯誤。

【小結】

在 PowerShell 呼叫函式時,請認明呼叫對象是 .NET 方法還是 PowerShell 函式,若是 PowerShell 函式,請遵循 FunctionName Param1 Param2 Param3... 寫法,不要加括號,也不要加逗號,參數間用空白間隔。

It's confusing for .NET developer to call PowerShell function with mutliple parameters, this article provides some syntax tips.


Comments

# by 凱大

追加一個同等類型的陷阱 powershell 可以以檔案名稱作為function name 如果在這種情況下要帶參數的寫法則是再開頭加上 param ex: param($arg) 但如果下意識地寫上 param($arg) { //script...... } 那powershell 就會把語法視為content 輸出

Post a comment