PowerShell - 將多參數以陣列變數傳入函式
0 |
分享最近學到的 PowerShell 小技巧。
假設我有個接受多個參數的函式,有三種參數寫法。第一種是寫成 FuncName Arg1 Arg2 Arg3... 依序列出,中間以空白間隔(注意:不要加 ( ) 及 ,,參考:函式多參數寫法陷阱);第二種則是參數值前方加上名稱,如此可不依順序,如:FuncName -Arg3 Arg3 -Arg1 Arg1 -Arg2 Arg2;第三種則是混合,前幾個依序,後方選擇性參數以具名方式指定,例如:FuncName Arg1 -Arg3 Arg3。
#函式接受三個參數組成特定格式字串
function PrintRecord(
[string]$brand, [string]$model, [int]$year
)
{
Write-Host "[$brand] $model - $year"
}
# 函式多參數寫法 REF:
# 依序傳入
PrintRecord "Thinkpad" "X21" 2001
# 具名傳入
PrintRecord -brand "Thinkpad" -year 2001 -model "X21"
# 依序+具名混合
PrintRecord 2001 -brand "Thinkpad" -model "X21"
問題來了,在以上的例子,如果參數來自資料庫或 CSV,每一筆的 $brand、$model、$year 存在三元素陣列中,要怎麼傳給 PrintRecord?
不想花腦筋的話,在迴圈寫死 PrintRecord $ary[0] $ary[1] $ary[2] 就好,但,有沒有簡潔一點的做法?
學到一個新名詞 - Splatting,關鍵是將陣列或雜湊表變數 $varName 的「$」改成「@」,寫成 @varName。若變數為陣列,PowerShell 將展開陣列以第一個元素對映第一個參數、第二個元素對映第二個參數... 以此類推;若變數為雜湊表,則相當於轉成 -key1 value1 -key2 value2 -key3 value3... 以此類推。如以下範例:
$data = (
("Thinkpad","X21", 2001),
("VAIO","T13", 2012),
("Thinkpad","T470p", 2017)
)
# 標準寫法
$data | ForEach-Object {
PrintRecord $_[0] $_[1] $_[2]
}
# 原本 $_ 為陣列,改寫為 @_ 相當於將陣列元素依序對映函式參數
$data | ForEach-Object { PrintRecord @_ }
# 用 Hashtable 對映參數名稱及參數值,可以不依順序傳入參數
$data | ForEach-Object {
$p = @{
model = $_[1];
year = $_[2];
brand = $_[0];
}
# $p 改寫成 @p 會依 Hashtable Key 對映參數名稱
PrintRecord @p
}
最後來個 $ 與 @ 的小測驗,我讓 F 函式的 $p1 可以接受陣列也可以接受字串,藉以觀察 $ 與 @ 結果差異。大家先猜猜結果為何,再看答案。
function F($p1, $p2 = $null) {
Write-Host "`$p1[$($p1.GetType())] = $p1, `$p2 = $p2"
}
$array = ("P1", "P2")
# $array 視為單一參數,對映 $p1
F $array
# @array 將陣列展開,分別對映 $p1, $p2
F @array
F "P1" "P2"
F ("P1","P2")
# 陣列宣告前方的 @ 是 Array Sub-Expression Operator
# 無 Splatting 效果
F @("P1", "P2")
應該不難吧?只有最後一行是陷阱,F @("P1", "P2") 並不會形成 Splatting,因為陣列前方的 @ 將被解讀成 Array Sub-Expression Operator,而非 Splatting 符號。
Exmample of how to use platting to pass array as multiple arguemnts to fucntion in PowerShell.
Comments
Be the first to post a comment