寫了一陣子 PowerShell,發覺自己跟它的陣列很不熟,老想著用 .NET LINQ 思維解題,有點吃力不討好。其實,PowerShell 陣列語法比 C# 靈活(例如: 索引可以是負數、用 .. 表示區間,+ 表示相對位置,註:C# 8.0 有加入一些)、ForEach()、Where() 也有類似 LINQ 的功能,靠 PowerShell 就能輕巧快速完成工作,不一定要繞路 .NET 方式。我把官方文件掃了一次,發現不少先前忽略的技巧,以程式加註解形式寫成筆記備忘兼分享:

# PowerShell 陣列筆記

# 宣告方式

# 直接逗號分隔
$csv = 1, 3, 5, 7, 9

# 數字可以用 x..y 標區間
$range = 10..15

# 不註明型別一律為 object[]
"$($csv.GetType()) $($range.GetType())" #System.Object[] System.Object[]

# 加型別宣告或轉型可指定型別
[int[]] $intAry = 1..8
$procList = [System.Diagnostics.Process[]](Get-Process)
"$($intAry.GetType()) $($procList.GetType())" #int[] System.Diagnostics.Process[]

# Array Operator @
$empty = @()
$oneStrArray = @("Hello")
"$($empty.Count) $($oneStrArray.Count)" # 0 1

# 由 0 起始,用 [n] 取第 n 個元素,用法跟 C# 相近
$procArray = $(Get-Process)
$procArray[0].Name
# 索引值可用..取區間
$procArray[1..2]
#Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
#-------  ------    -----      -----     ------     --  -- -----------
#612      36    27656      20720       4.59  14224   1 ApplicationFrameHost
#234      13     9248      16488       0.20  32088   0 audiodg
# 負數索引由後向前取
$tenNums = 0..9
$tenNums[-1..-2] | ConvertTo-Json #9 8
# 還可以正負相串
$tenNums[1..-1] | ConvertTo-Json #1 0 9
# + 向後第幾個
$tenNums[0..2 + 4..5] | ConvertTo-Json #0 1 2 4 5

# 二維陣型
[int[, ]] $twoDim = [int[, ]]::new(5, 5)
$twoDim[3, 3]

# 將陣列元素清成 default 值, int 的話變 0
$tenNums.Clear()

# ForEach 對陣列所有元素做動作
$tenNums = 0..9
$tenNums.ForEach( { $_ * 2 }) # 0 2 4 6 8 ...
# ForEach 批次轉型 (LINQ .Cast<>())
@("2005/1/1", "2014/6/3", "2020/6/5").ForEach([datetime]).ForEach([string])
#01/01/2005 00:00:00
#06/03/2014 00:00:00
#06/05/2020 00:00:00
# ForEach 取屬性及設定屬性 (LINQ .Select() / .ForEach())
(dir 'd:\TEMP\*.txt').ForEach('LastWriteTime')
(dir 'd:\Temp\*.txt').ForEach('LastWriteTime', (Get-Date))
# ForEach 執行方法
("a", "b", "c").ForEach("ToUpper") # A B C

# Where
(0..9).Where( { $_ % 2 -eq 0 }) # 0 2 4 6 8 
(0..9).Where( { $_ % 2 -eq 0 }, 'First', 2) # 0 2
(0..9).Where( { $_ % 2 -eq 0 }, 'Last', 3) # 4 6 8
(0..9).Where( { $_ -eq 5 }, 'SkipUntil') # 5 6 7 8 9
(0..9).Where( { $_ -eq 5 }, 'SkipUntil', 2) # 5 6
(0..9).Where( { $_ -eq 5 }, 'Until') # 0 1 2 3 4
(0..9).Where( { $_ -eq 5 }, 'Until', 3) # 0 1 2

# 依條件分群,拆成兩個陣列
$even, $odd = (0..9).Where( { $_ % 2 -eq 0}, 'Split') 
# $even = 0 2 4 6 8
# $odd = 1 3 5 7 9

# 設定元素值
$a = 0..5
$a[1] = -1
$a.Set(2, -2)
$a += 6 # 在後方加上元素 
# 會複製陣列新增傳回新陣列,跟 string += 一樣,效能不優

# 挑選元素產生新陣列
$s = 0..9
$n = $s[0,1+7..($s.Length - 2)]
# $n = 0 1 7 8 

# 陣列相加 
$a = 0..1
$b = 4..5
$c = $a + $b # $c = 0 1 4 5

# 刪除陣列釋出空間
$a = $null 
Remoive-Item $b

# 新增及刪除元素
# PowerShell 陣列是 Array 不能增刪元素,我找到較簡單的做法是轉型成 ArrayList
# 增刪完元素再轉回來 (如果有需要的話)

$a = 0..5
# $a.Remove(1) 會產生 "Collection was of a fixed size." 錯誤
$t = [System.Collections.ArrayList]$a
$t.Remove(3)
$a = [int[]]$t
$a # 0 1 2 4 5

Notes of PowerShell arrays.


Comments

Be the first to post a comment

Post a comment