about_Hash_Tables
简短说明
介绍如何在 PowerShell 中创建、使用哈希表以及对哈希表进行排序。
长说明
哈希表(也称为字典或关联数组)是一种压缩的数据结构,用于存储一个或多个键值对。 例如,哈希表可能包含一系列 IP 地址和计算机名,其中 IP 地址是键,计算机名是值,反之亦然。
在 PowerShell 中,每个哈希表都是 [System.Collections.Hashtable]
对象。 可以在 PowerShell 中使用 Hashtable 对象的属性和方法。
从 PowerShell 3.0 开始,可以使用 [ordered]
类型加速器在 PowerShell 中创建 [System.Collections.Specialized.OrderedDictionary]
对象。
有序字典与哈希表的不同之处在于,键始终按照其列出顺序出现。 哈希表中键的顺序不是确定性的。
哈希表中的键和值也是 .NET 对象。 它们通常是字符串或整数,但可以采用任何对象类型。 还可以创建嵌套哈希表,其中键的值是另一个哈希表。
哈希表通常用于查找和检索数据。 可以使用哈希表来存储列表以及在 PowerShell 中创建计算属性。 而且,ConvertFrom-StringData
cmdlet 会将结构化字符串数据转换为哈希表。
语法
哈希表的语法如下所示:
@{ <name> = <value>; [<name> = <value> ] ...}
有序字典的语法如下:
[ordered]@{ <name> = <value>; [<name> = <value> ] ...}
PowerShell 3.0 中引入了 [ordered]
类型加速器。
若要创建哈希表,请遵循以下准则:
- 使用 at 符号(
@
)开始哈希表。 - 将哈希表括在大括号 (
{}
) 中。 - 为哈希表的内容输入一个或多个键值对。
- 使用等号 (
=
) 分隔每个键与其值。 - 使用分号 (
;
) 或换行符分隔键值对。 - 包含空格的键必须括在引号中。 值必须是有效的 PowerShell 表达式。 即使字符串不包含空格,也必须在引号中显示。
- 若要管理哈希表,请将其保存在变量中。
- 将有序哈希表分配给变量时,请将
[ordered]
类型置于@
符号之前。 如果将其放在变量名称之前,命令将会失败。
可以像使用哈希表一样使用有序字典。 任何一种类型都可以用作接受哈希表或字典 (iDictionary) 类型对象的参数的值。
创建哈希表和有序字典
请考虑以下哈希表和有序字典示例:
$hash = @{
1 = 'one'
2 = 'two'
'three' = 3
}
$hash
Name Value
---- -----
three 3
2 two
1 one
如您所见,哈希表中的键值对并未按照其定义顺序显示。
创建有序字典的最简单方法是使用 [ordered]
属性。 将属性放在符号前面 @
。
$dictionary = [ordered]@{
1 = 'one'
2 = 'two'
'three' = 3
}
$dictionary
Name Value
---- -----
1 one
2 two
three 3
与哈希表不同,有序字典维护键值的顺序。
转换哈希表和有序字典
不能使用 [ordered]
类型快捷键转换或强制转换哈希表。
如果将有序属性放在变量名称之前,则命令会失败并显示以下错误消息。
[ordered]$orderedhash = @{}
ParserError:
Line |
1 | [ordered]$orderedhash = @{}
| ~~~~~~~~~~~~~~
| The ordered attribute can be specified only on a hash literal node.
若要更正表达式,请移动 [ordered] 属性。
$orderedhash = [ordered]@{}
可以将有序字典强制转换为哈希表,但不能保证成员的顺序。
[hashtable]$newhash = [ordered]@{
Number = 1
Shape = "Square"
Color = "Blue"
}
$newhash
Name Value
---- -----
Color Blue
Shape Square
Number 1
Hashtable 和字典属性
哈希表和有序字典共享多个属性。 $hash
请考虑前面示例中定义的变量和$dictionary
变量。
$hash | Get-Member -MemberType Properties, ParameterizedProperty
TypeName: System.Collections.Hashtable
Name MemberType Definition
---- ---------- ----------
Item ParameterizedProperty System.Object Item(System.Object key) {get;set;}
Count Property int Count {get;}
IsFixedSize Property bool IsFixedSize {get;}
IsReadOnly Property bool IsReadOnly {get;}
IsSynchronized Property bool IsSynchronized {get;}
Keys Property System.Collections.ICollection Keys {get;}
SyncRoot Property System.Object SyncRoot {get;}
Values Property System.Collections.ICollection Values {get;}
$dictionary | Get-Member -MemberType Properties, ParameterizedProperty
TypeName: System.Collections.Specialized.OrderedDictionary
Name MemberType Definition
---- ---------- ----------
Item ParameterizedProperty System.Object Item(int index) {get;set;},
System.Object Item(System.Object key) {get;set;}
Count Property int Count {get;}
IsFixedSize Property bool IsFixedSize {get;}
IsReadOnly Property bool IsReadOnly {get;}
IsSynchronized Property bool IsSynchronized {get;}
Keys Property System.Collections.ICollection Keys {get;}
SyncRoot Property System.Object SyncRoot {get;}
Values Property System.Collections.ICollection Values {get;}
最常用的属性是 Count、 Keys、 Values 和 Item。
指示 对象中的键值对数的 Count 属性。
Keys 属性是哈希表或字典中的键名集合。
PS> $hash.Keys three 2 1 PS> $dictionary.Keys 1 2 three
Values 属性是哈希表或字典中的值的集合。
PS> $hash.Values 3 two one PS> $dictionary.Values one two 3
Item 属性是一个参数化属性,返回指定的项的值。 哈希表使用键作为参数化属性的参数,而字典默认使用索引。 此差异会影响访问每种类型的值的方式。
访问值
可通过两种常见方法来访问哈希表或字典中的值:成员表示法或数组索引表示法。
成员表示法 - 可以使用键名称作为对象的成员属性来访问值。 例如:
PS> $hash.1 one PS> $dictionary.2 two
数组索引表示法 - 可以使用索引表示法访问值。 PowerShell 将该表示法转换为对 对象的 Item 参数化属性的调用。
将索引表示法用于哈希表时,括号内的值为键名称。 如果键是字符串值,请将键名称括在引号中。 例如:
PS> $hash['three'] 3 PS> $hash[2] two
在此示例中,键值
2
不是值集合中的索引。 它是键值对中的键值。 可以通过索引到值的集合来证明这一点。PS> ([array]$hash.Values)[2] one
在字典中使用索引表示法时,括号内的值会根据其类型进行解释。 如果值为整数,则将其视为值集合中的索引。 如果值不是整数,则它被视为键名称。 例如:
PS> $dictionary[1] two PS> ([array]$dictionary.Values)[1] two PS> $dictionary[[object]1] one PS> $dictionary['three'] 3
在此示例中,数组值
[1]
是使用Item(int index)
参数化属性重载的值集合中的索引。 数组值[[object]1]
不是索引,而是使用重载的Item(System.Object key)
键值。注意
当键值为整数时,此行为可能会令人困惑。 如果可能,应避免在字典中使用整数键值。
处理属性名称冲突
如果键名与 HashTable 类型的属性名称之一冲突,可以使用 psbase 内在成员来访问这些属性。 例如,如果密钥名称 keys
并且想要返回 HashTable 键的集合,请使用以下语法:
$hashtable.psbase.Keys
此要求适用于实现 System.Collections.IDictionary 接口的其他类型,例如 OrderedDictionary。
迭代键和值
可以循环访问哈希表中的键,以多种方式处理值。 本部分的每个示例都会生成相同的输出。 它们迭代此处定义的 $hash
变量:
$hash = [ordered]@{Number = 1; Shape = "Square"; Color = "Blue"}
注意
在这些示例中, $hash
定义为有序字典,以确保输出始终按相同的顺序。 这些示例适用于标准哈希表,但输出的顺序不可预测。
每个示例针对每个键及其值返回一条消息:
The value of 'Number' is: 1
The value of 'Shape' is: Square
The value of 'Color' is: Blue
此示例使用块 foreach
循环访问密钥。
foreach ($Key in $hash.Keys) {
"The value of '$Key' is: $($hash[$Key])"
}
此示例使用 ForEach-Object
来迭代键。
$hash.Keys | ForEach-Object {
"The value of '$_' is: $($hash[$_])"
}
此示例使用 GetEnumerator()
该方法通过管道 ForEach-Object
将每个键值对发送到 。
$hash.GetEnumerator() | ForEach-Object {
"The value of '$($_.Key)' is: $($_.Value)"
}
此示例使用 GetEnumerator()
和 ForEach()
方法循环访问每个键值对。
$hash.GetEnumerator().ForEach({"The value of '$($_.Key)' is: $($_.Value)"})
添加和删除键与值
通常,在创建哈希表时,在定义中包含键值对。 但是,可以随时从哈希表添加和删除键值对。 以下示例创建一个空哈希表。
$hash = @{}
可以使用数组表示法添加键值对。 例如,以下示例向哈希表添加 Time
键,其值为 Now
。
$hash["Time"] = "Now"
还可以使用 System.Collections.Hashtable 对象的 Add()
方法向哈希表添加键和值。 Add()
方法采用以下语法:
Add(Key, Value)
例如,若要向哈希表添加具有 Now
值的 Time
键,请使用以下语句格式。
$hash.Add("Time", "Now")
此外,可以使用加法运算符(+
)向哈希表添加键和值,将哈希表添加到现有哈希表。 例如,以下语句向 $hash
变量中的哈希表添加一个 Time
键,其值 Now
。
$hash = $hash + @{Time="Now"}
还可以添加存储在变量中的值。
$t = "Today"
$now = (Get-Date)
$hash.Add($t, $now)
不能使用减法运算符从哈希表中删除键值对,但可以使用哈希表对象的 Remove()
方法。 Remove
方法采用以下语法:
$object.Remove(<key>)
以下示例从Time
$hash
中删除键值对。
$hash.Remove("Time")
哈希表中的对象类型
哈希表中的键和值可以具有任何 .NET 对象类型,单个哈希表可以具有多个类型的键和值。
以下语句创建进程名称字符串和进程对象值的哈希表,并将其保存在 $p
变量中。
$p = @{
"PowerShell" = (Get-Process PowerShell)
"Notepad" = (Get-Process notepad)
}
可以在 $p
中显示哈希表,并使用键名称属性显示值。
PS> $p
Name Value
---- -----
PowerShell System.Diagnostics.Process (PowerShell)
Notepad System.Diagnostics.Process (notepad)
PS> $p.PowerShell
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
441 24 54196 54012 571 5.10 1788 PowerShell
PS> $p.Keys | ForEach-Object {$p.$_.Handles}
441
251
哈希表中的键可以是任何 .NET 类型。 以下语句将键值对添加到 $p
变量中的哈希表。 键是代表 WinRM 服务的 Service 对象,值是服务的当前状态。
$p = $p + @{
(Get-Service WinRM) = ((Get-Service WinRM).Status)
}
可以使用哈希表中其他对所使用的相同方法显示和访问新的键值对。
PS> $p
Name Value
---- -----
PowerShell System.Diagnostics.Process (PowerShell)
Notepad System.Diagnostics.Process (notepad)
System.ServiceProcess.Servi... Running
PS> $p.Keys
PowerShell
Notepad
Status Name DisplayName
------ ---- -----------
Running winrm Windows Remote Management (WS-Manag...
PS> $p.Keys | ForEach-Object {$_.Name}
WinRM
哈希表中的键和值也可以是 Hashtable 对象。 以下语句将键值对添加到 $p
变量中的哈希表,其中键为字符串,Hash2,值为具有三个键值对的哈希表。
$p = $p + @{
"Hash2"= @{a=1; b=2; c=3}
}
可以使用相同的方法显示和访问新值。
PS> $p
Name Value
---- -----
PowerShell System.Diagnostics.Process (pwsh)
Hash2 {[a, 1], [b, 2], [c, 3]}
Notepad System.Diagnostics.Process (Notepad)
WinRM Running
PS> $p.Hash2
Name Value
---- -----
a 1
b 2
c 3
PS> $p.Hash2.b
2
对键和值进行排序
哈希表中的项本质上是无序的。 每次显示键值对时,它们可能会以不同的顺序显示。
虽然无法对哈希表进行排序,但可以使用哈希表的 GetEnumerator()
方法来枚举键和值,然后使用 Sort-Object
cmdlet 对枚举值进行排序以显示。
例如,以下命令枚举 $p
变量中哈希表的键和值,然后按字母顺序对键进行排序。
PS> $p.GetEnumerator() | Sort-Object -Property key
Name Value
---- -----
Hash2 {[a, 1], [b, 2], [c, 3]}
Notepad System.Diagnostics.Process (Notepad)
PowerShell System.Diagnostics.Process (pwsh)
WinRM Running
以下命令使用相同的过程按降序对哈希值进行排序。
PS> $p.GetEnumerator() | Sort-Object -Property Value -Descending
Name Value
---- -----
PowerShell System.Diagnostics.Process (pwsh)
Notepad System.Diagnostics.Process (Notepad)
Hash2 {[a, 1], [b, 2], [c, 3]}
WinRM Running
从哈希表创建对象
从 PowerShell 3.0 开始,可以从属性和属性值的哈希表创建对象。
语法如下:
[<class-name>]@{
<property-name>=<property-value>
<property-name>=<property-value>
}
此方法仅适用于具有无参数构造函数的类。 对象属性必须是公共且可设置的。
有关详细信息,请参阅 about_Object_Creation。
ConvertFrom-StringData
ConvertFrom-StringData
cmdlet 将字符串或键值对的 here-string 转换为哈希表。 可以在脚本的 Data 部分安全地使用 ConvertFrom-StringData
cmdlet,并且可以将其与 Import-LocalizedData
cmdlet 配合使用,以当前用户的用户界面 (UI) 区域性显示用户消息。
当哈希表中的值包含引号时,Here-字符串特别有用。 有关 here-string 的详细信息,请参阅 about_Quoting_Rules。
以下示例演示如何在上一示例中创建用户消息的此处字符串,以及如何使用 ConvertFrom-StringData
将它们从字符串转换为哈希表。
以下命令创建键值对的 here-string,然后将其保存在 $string
变量中。
$string = @"
Msg1 = Type "Windows".
Msg2 = She said, "Hello, World."
Msg3 = Enter an alias (or "nickname").
"@
此命令使用 ConvertFrom-StringData
cmdlet 将此处的字符串转换为哈希表。
ConvertFrom-StringData $string
Name Value
---- -----
Msg3 Enter an alias (or "nickname").
Msg2 She said, "Hello, World."
Msg1 Type "Windows".
有关 here-string 的详细信息,请参阅 about_Quoting_Rules。