about_Hash_Tables

简短说明

介绍如何在 PowerShell 中创建、使用哈希表以及对哈希表进行排序。

长说明

哈希表也称为字典或关联阵列,是用于存储一个或多个键值对的紧凑数据结构。 例如,哈希表可能包含一系列 IP 地址和计算机名,其中 IP 地址是键,计算机名是值,反之亦然。

在 PowerShell 中,每个哈希表都是一个 Hashtable[System.Collections.Hashtable] 对象。 可以在 PowerShell 中使用 Hashtable 对象的属性和方法。

从 PowerShell 3.0 开始,可以使用 [ordered] 属性在 PowerShell 中创建 [System.Collections.Specialized.OrderedDictionary] 对象。

有序字典与哈希表的不同之处在于,键始终按照其列出顺序出现。 哈希表中的键顺序是不确定的。

哈希表中的键和值也是 .NET 对象。 它们通常是字符串或整数,但可以采用任何对象类型。 你还可以创建嵌套哈希表,其中键的值是另一个哈希表。

经常会使用 Hashtable,因为它们对于查找和检索数据非常有效。 可以使用哈希表来存储列表以及在 PowerShell 中创建计算属性。 另外,PowerShell 有一个 cmdlet ConvertFrom-StringData,它可以将字符串转换为哈希表。

语法

哈希表的语法如下:

@{ <name> = <value>; [<name> = <value> ] ...}

有序字典的语法如下:

[ordered]@{ <name> = <value>; [<name> = <value> ] ...}

PowerShell 3.0 中引入了 [ordered] 类型加速器。

创建哈希表

若要创建哈希表,请遵循以下准则:

  • 哈希表以 at 符号 (@) 开头。
  • 将哈希表括在大括号 ({}) 中。
  • 输入一个或多个键值对作为哈希表的内容。
  • 使用等号 (=) 分隔每个键与其值。
  • 使用分号 (;) 或换行符分隔键值对。
  • 包含空格的键必须括在引号中。 值必须是有效的 PowerShell 表达式。 即使字符串不包含空格,也必须在引号中显示。
  • 若要管理哈希表,请将其保存在变量中。
  • 将有序哈希表分配到变量时,请将 [ordered] 类型放在 @ 符号之前。 如果将其放在变量名称之前,命令将会失败。

若要在 $hash 的值中创建一个空哈希表,请键入:

$hash = @{}

还可以在创建哈希表时将键和值添加到哈希表中。 例如,以下语句创建包含三个键的哈希表。

$hash = @{ Number = 1; Shape = "Square"; Color = "Blue"}

创建有序字典

可以通过添加 OrderedDictionary 类型的对象来创建有序字典,但创建有序字典的最简单方法是使用 [ordered] 属性。

PowerShell 3.0 中引入了 [ordered] 属性。

将属性放置在“@”符号之前。

$hash = [ordered]@{ Number = 1; Shape = "Square"; Color = "Blue"}

可以像使用哈希表一样使用有序字典。 任一类型都可以用作采用哈希表或字典 (iDictionary) 的参数的值。

不能使用 [ordered] 属性来转换或强制转换哈希表。 如果将有序属性放在变量名称之前,则命令会失败并显示以下错误消息。

[ordered]$hash = @{}
ParserError:
Line |
   1 |  [ordered]$hash = @{}
     |  ~~~~~~~~~~~~~~
     | The ordered attribute can be specified only on a hash literal node.

若要更正表达式,请移动 [ordered] 属性。

$hash = [ordered]@{}

可以将有序字典强制转换为哈希表,但无法恢复有序属性,即使清除变量并输入新值也是如此。 若要重新建立顺序,必须删除再重新创建变量。

[hashtable]$hash = [ordered]@{
  Number = 1; Shape = "Square"; Color = "Blue"}
$hash
Name                           Value
----                           -----
Color                          Blue
Shape                          Square
Number                         1

显示哈希表

若要显示保存在变量中的哈希表,请键入变量名称。 默认情况下,哈希表以表格形式显示,其中的一列是键,另一列是值。

$hash
Name                           Value
----                           -----
Shape                          Square
Color                          Blue
Number                         1

哈希表具有 Keys 和 Values 属性。 使用点表示法显示所有键或所有值。

$hash.keys
Number
Shape
Color
$hash.values
1
Square
Blue

每个键名也是哈希表的一个属性,其值是键名属性的值。 使用以下格式显示属性值。

$hashtable.<key>
<value>

例如:

$hash.Number
1

$hash.Color
Blue

哈希表有一个 Count 属性,该属性指示哈希表中键值对的数量

$hash.count
3

哈希表不是数组,因此你不能使用整数作为哈希表中的索引,但可以使用键名作为哈希表中的索引。 如果键是字符串值,请将键名括在引号中。

例如:

$hash["Number"]
1

处理属性名称冲突

如果键名与 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["<key>"] = "<value>"

例如,若要将值为“Now”的“Time”键添加到哈希表,请使用以下语句格式。

$hash["Time"] = "Now"

还可以使用 System.Collections.Hashtable 对象的 Add 方法将键和值添加到哈希表。 Add 方法采用以下语法:

Add(Key, Value)

例如,若要将值为 NowTime 键添加到哈希表,请使用以下语句格式。

$hash.Add("Time", "Now")

并且,可以使用加法运算符 (+) 将键和值添加到哈希表,以将哈希表添加到现有哈希表。 例如,以下语句将值为 NowTime 键添加到 $hash 变量中的哈希表。

$hash = $hash + @{Time="Now"}

还可以添加存储在变量中的值。

$t = "Today"
$now = (Get-Date)

$hash.Add($t, $now)

无法使用减法运算符从哈希表中删除键值对,但可以使用 Hashtable 对象的 Remove 方法。 Remove 方法将键作为其值。

Remove 方法采用以下语法:

Remove(Key)

例如,若要从 $hash 变量值中的哈希表中删除 Time=Now 键值对,请键入:

$hash.Remove("Time")

可以在 PowerShell 中使用 Hashtable 对象的所有属性和方法,包括 ContainsClearCloneCopyTo。 有关 Hashtable 对象的详细信息,请参阅 System.Collections.Hashtable

哈希表中的对象类型

哈希表中的键和值可以采用任何 .NET 对象类型,单个哈希表可以采用多种类型的键和值。

以下语句创建进程名称字符串和进程对象值的哈希表,并将其保存在 $p 变量中。

$p = @{
    "PowerShell" = (Get-Process pwsh)
    "Notepad" = (Get-Process notepad)
}

可以在 $p 中显示哈希表并使用键名属性来显示值。

PS> $p

Name                           Value
----                           -----
PowerShell                     System.Diagnostics.Process (pwsh)
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}
774
824

哈希表中的键可以是任何 .NET 类型。 以下语句将键值对添加到 $p 变量中的哈希表。 键是代表 WinRM 服务的 Service 对象,值是服务的当前状态

$p = $p + @{
    (Get-Service WinRM) = ((Get-Service WinRM).Status)
}

可以像针对哈希表中的其他键值对一样显示和访问新的键值对。

PS> $p

Name                           Value
----                           -----
PowerShell                     System.Diagnostics.Process (pwsh)
WinRM                          Running
Notepad                        System.Diagnostics.Process (Notepad)

PS> $p.keys
PowerShell

Status   Name               DisplayName
------   ----               -----------
Running  WinRM              Windows Remote Management (WS-Managem…
Notepad

哈希表中的键和值也可以是 Hashtable 对象。 以下语句将键值对添加到 $p 变量中的哈希表,其中的键是字符串 Hash2,值是包含三个键值对的哈希表。

$p = $p + @{
    "Hash2"= @{a=1; b=2; c=3}
}

可以使用相同的方法显示和访问新值。

PS> $p

Name                           Value
----                           -----
WinRM                          Running
Hash2                          {a, b, c}
PowerShell                     System.Diagnostics.Process (pwsh)
Notepad                        System.Diagnostics.Process (Notepad)

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, b, c}
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, b, c}
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-string 特别有用。 有关 here-string 的详细信息,请参阅 about_Quoting_Rules

以下示例演示如何创建上一示例中用户消息的 here-string,以及如何使用 ConvertFrom-StringData 将其从字符串转换为哈希表。

以下命令创建键值对的 here-string,然后将其保存在 $string 变量中。

$string = @"
Msg1 = Type "Windows".
Msg2 = She said, "Hello, World."
Msg3 = Enter an alias (or "nickname").
"@

此命令使用 ConvertFrom-StringData cmdlet 将 here-string 转换为哈希表。

ConvertFrom-StringData $string

Name                           Value
----                           -----
Msg3                           Enter an alias (or "nickname").
Msg2                           She said, "Hello, World."
Msg1                           Type "Windows".

有关 here-string 的详细信息,请参阅 about_Quoting_Rules

另请参阅