windows-运维-07 数组和哈希表

windows-运维-07 数组和哈希表

命令返回数组

当我们把一个命令的执行结果保存到一个变量中,可能会认为变量存放的是纯文本。
  但是,事实上Powershell会把文本按每一行作为元素存为数组。如果一个命令的返回值不止一个结果时,Powershell也会自动把结果存储为数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
PS C:Powershell> $IPcfg=ipconfig
PS C:Powershell> $IPcfg

Windows IP Configuration
Ethernet adapter Local Area Connection:
Connection-specific DNS Suffix . : ***
Link-local IPv6 Address . . . . . : ***
IPv4 Address. . . . . . . . . . . : 192.168.140.128
Subnet Mask . . . . . . . . . . . : 255.255.252.0
Default Gateway . . . . . . . . . : 192.168.140.1

Tunnel adapter isatap.eagleslab.com:

Connection-specific DNS Suffix . : ***
Link-local IPv6 Address . . . . . : ***
Default Gateway . . . . . . . . . :***

Tunnel adapter Teredo Tunneling Pseudo-Interface:

Media State . . . . . . . . . . . : Media disconnected
Connection-specific DNS Suffix . :
PS C:Powershell> $IPcfg.Count
22

使用数组存储结果

判断一个变量是否为数组

1
2
3
4
5
6
7
8
PS C:Powershell> $ip=ipconfig
PS C:Powershell> $ip -is [array]
True
PS C:Powershell> "abac" -is [array]
False
PS C:Powershell> $str="字符串"
PS C:Powershell> $str.ToCharArray() -is [array]
True

查看数组的元素个数用$array.Count属性。访问第x个元素,使用$array[x-1],因为数组是以0开始索引的。

1
2
3
4
5
6
PS C:Powershell> ipconfig | Select-String "IP"

Windows IP Configuration
Link-local IPv6 Address . . . . . : ***
IPv4 Address. . . . . . . . . . . : ***
Link-local IPv6 Address . . . . . : ***

使用真实的对象操作

  为什么不愿把IPconfig返回的结果称为对象,因为它不是真正Cmdlet命令,真正的Powershell命令返回的数组元素可不止一个字符串,它是一个内容丰富的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
PS C:Powershell> ls

Directory: C:Powershell

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 2011/11/23 17:25 ABC
d---- 2011/11/29 18:21 myscript
-a--- 2011/11/24 18:30 67580 a.html
-a--- 2011/11/24 20:04 26384 a.txt
-a--- 2011/11/24 20:26 12060 alias
-a--- 2011/11/24 20:27 12060 alias.ps1
-a--- 2011/11/23 17:25 0 b.txt
-a--- 2011/11/23 17:25 0 c.txt
-a--- 2011/11/23 17:25 0 d.txt
-a--- 2011/11/25 11:20 556 employee.xml
-a--- 2011/11/29 19:23 21466 function.ps1
-a--- 2011/11/28 11:12 186 LogoTestConfig.xml
-a--- 2011/11/24 17:37 7420 name.html
-a--- 2011/11/28 15:30 63 ping.bat
-a--- 2011/11/24 17:44 735892 Powershell_Cmdlets.html
-a--- 2011/11/30 16:04 2556 psdrive.html
-a--- 2011/12/2 18:47 140 test.ps1
-a--- 2011/11/23 17:37 242 test.txt
-a--- 2011/11/28 16:42 170 test.vbs
PS C:Powershell> $result=ls
PS C:Powershell> $result.Count
20

  数组的每一个元素存放的是一个System.IO.DirectoryInfo对象。当我们输出这些对象时,Powershell会自动帮我们把它转换成友好的文本格式。

1
2
3
4
5
6
7
PS C:Powershell> $result[0].gettype().fullname
System.IO.DirectoryInfo
PS C:Powershell> $result[0]
Directory: C:Powershell
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 2011/11/23 17:25 ABC

对于任何一个对象都可以使用Format-List * 查看它所有的属性和方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
PS C:Powershell> $result[0] | fl *

PSPath : Microsoft.PowerShell.CoreFileSystem::C:PowershellABC
PSParentPath : Microsoft.PowerShell.CoreFileSystem::C:Powershell
PSChildName : ABC
PSDrive : C
PSProvider : Microsoft.PowerShell.CoreFileSystem
PSIsContainer : True
BaseName : ABC
Mode : d----
Name : ABC
Parent : Powershell
Exists : True
Root : C:
FullName : C:PowershellABC
Extension :
CreationTime : 2011/11/23 17:25:53
CreationTimeUtc : 2011/11/23 9:25:53
LastAccessTime : 2011/11/23 17:25:53
LastAccessTimeUtc : 2011/11/23 9:25:53
LastWriteTime : 2011/11/23 17:25:53
LastWriteTimeUtc : 2011/11/23 9:25:53
Attributes : Directory

创建数组

在Powershell中创建数组可以使用逗号。

1
2
3
4
5
6
PS C:Powershell> $nums=2,0,1,2
PS C:Powershell> $nums
2
0
1
2

对于连续的数字数组可以使用一个更快捷的方法

1
2
3
4
5
6
7
PS C:Powershell> $nums=1..5
PS C:Powershell> $nums
1
2
3
4
5

数组的多态

像变量一样如果数组中元素的类型为弱类型,默认可以存储不同类型的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
PS C:Powershell> $array=1,"2012世界末日",([System.Guid]::NewGuid()),(get-date)
PS C:Powershell> $array
1
2012世界末日

Guid
----
06a88783-a181-4511-9e41-2780ecbd7924

DisplayHint : DateTime
Date : 2011/12/9 0:00:00
Day : 9
DayOfWeek : Friday
DayOfYear : 343
Hour : 14
Kind : Local
Millisecond : 910
Minute : 15
Month : 12
Second : 45
Ticks : 634590369459101334
TimeOfDay : 14:15:45.9101334
Year : 2011
DateTime : 2011年12月9日 14:15:45

空数组和单元素数组

空数组

1
2
3
4
5
PS C:Powershell> $a=@()
PS C:Powershell> $a -is [array]
True
PS C:Powershell> $a.Count
0

1个元素的数组

1
2
3
4
5
PS C:Powershell> $a=,"moss"
PS C:Powershell> $a -is [array]
True
PS C:Powershell> $a.Count
1

访问数组

  数组的元素可以使用索引寻址,第一个元素的索引为0,第i个元素的索引为i-1,最后一个元素的索引为Count-1,但是Powershell为了使用方便,直接可以将 -1 作为最后的一个元素的索引。

1
2
3
4
5
6
7
8
9
PS C:Powershell> $books="元素1","元素2","元素3"
PS C:Powershell> $books[0]
元素1
PS C:Powershell> $books[1]
元素2
PS C:Powershell> $books[($book.Count-1)]
元素3
PS C:Powershell> $books[-1]
元素3

从数组中选择多个元素

1
2
3
4
5
6
7
8
9
10
PS C:Powershell> $result=ls
PS C:Powershell> $result[0,3,5,12]
Directory: C:Powershell

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 2011/11/23 17:25 ABC
-a--- 2011/11/24 20:04 26384 a.txt
-a--- 2011/11/24 20:27 12060 alias.ps1
-a--- 2011/11/24 17:37 7420 name.html

将数组逆序输出

1
2
3
4
5
PS C:Powershell> $books="元素1","元素2","元素3"
PS C:Powershell> $books[($books.Count)..0]
元素3
元素2
元素1

给数组添加和删除元素

  因为Powershell数组在内存中是顺序存储的,所以数组的大小必须是确定的,这样才方便分配存储空间,所以给数组增加元素其实相当于创建一个新的数组,只不过之后会把原来的副本删除。在当前数组追加元素可以使用“+=”操作符。

1
2
3
4
5
6
7
PS C:Powershell> $books="元素1","元素2","元素3"
PS C:Powershell> $books+="元素4"
PS C:Powershell> $books
元素1
元素2
元素3
元素4

要删除第三个元素可以使用以下命令:

1
2
3
4
5
6
7
8
9
10
11
PS C:Powershell> $num=1..4
PS C:Powershell> $num
1
2
3
4
PS C:Powershell> $num=$num[0..1]+$num[3]
PS C:Powershell> $num
1
2
4

复制数组

  数组属于引用类型,使用默认的的赋值运算符在两个变量之间赋值只是复制了一个引用,两个变量共享同一份数据。这样的模式有一个弊病如果其中一个改变也会株连到另外一个。所以复制数组最好使用Clone()方法,除非有特殊需求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PS C:Powershell> $chs=@("A","B","C")
PS C:Powershell> $chsBak=$chs
PS C:Powershell> $chsBak[1]="H"
PS C:Powershell> $chs
A
H
C
PS C:Powershell> $chs.Equals($chsBak)
True
PS C:Powershell> $chsNew=$chs.Clone()
PS C:Powershell> $chsNew[1]="Good"
PS C:Powershell> $chs.Equals($chsNew)
False
PS C:Powershell> $chs
A
H
C

强类型数组

  Powershell数组一般具有多态性,如果你不指定元素的具体类型,解释器会自动选择合适的类型存储每个元素。如果要统一限制所有元素的类型,可是使用类型名和一对方括号作为数组变量的类型。这样每当赋值时,会自动类型检查。如果目标数据类型不能转换成功,就会抛出一个异常。

1
2
3
4
5
6
7
8
9
10
PS C:Powershell> [int[]] $nums=@()
PS C:Powershell> $nums+=2012
PS C:Powershell> $nums+=12.3
PS C:Powershell> $nums+="999"
PS C:Powershell> $nums+="can not convert"
Cannot convert value "can not convert" to type "System.Int32". Error: "Input string was not in a correct format."
At line:1 char:6
+ $nums <<<< +="can not convert"
+ CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
+ FullyQualifiedErrorId : RuntimeException

使用哈希表

  哈希表存放的是对,在哈希表中不再仅仅限制使用数字寻址,可以使用任意类型的数据类型寻址。
创建哈希表
  之前使用@()创建数组,现在使用@{}创建哈希表,使用哈希表的键访问对应的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
PS C:Powershell> $stu=@{ Name = "小明";Age="12";sex="男" }
PS C:Powershell> $stu

Name Value
---- -----
Name 小明
Age 12
sex 男

PS C:Powershell> $stu["Name"]
小明
PS C:Powershell> $stu["age"]
12
PS C:Powershell> $stu.Count
3
PS C:Powershell> $stu.Keys
Name
Age
sex
PS C:Powershell> $stu.Values
小明
12

在哈希表中存储数组

可以在创建哈希表时就使用数组,因为创建数组和哈希表的的元素关键字不冲突。一个是逗号,一个是分号。

1
2
3
4
5
6
7
8
9
PS C:Powershell>  $stu=@{ Name = "小明";Age="12";sex="男";Books="三国演义","围城","哈姆雷特" }
PS C:Powershell> $stu

Name Value
---- -----
Books {三国演义, 围城, 哈姆雷特}
Name 小明
Age 12
sex 男

在哈希表中插入新的键值

在哈希表中插入新的键值很方便,象定义变量一样,可以直接拿来使用

1
2
3
4
5
6
7
8
9
PS C:Powershell> $Student=@{}
PS C:Powershell> $Student.Name="令狐冲"
PS C:Powershell> $Student.School="华山派"
PS C:Powershell> $Student

Name Value
---- -----
Name 令狐冲
School 华山派

哈希表值的更新和删除

如果要更新键的值,可以直接重写。如果要删除这个键值对,可以使用Remove方法,参数为Key

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
PS C:Powershell> $stu

Name Value
---- -----
Books {三国演义, 围城, 哈姆雷特}
Name 小明
Age 12
sex 男

PS C:Powershell> $stu.Name="赵强"
PS C:Powershell> $stu.Name
赵强
PS C:Powershell> $stu.Remove("Name")
PS C:Powershell> $stu

Name Value
---- -----
Books {三国演义, 围城, 哈姆雷特}
Age 12
sex 男

使用哈希表格式化输出

  在Powershell中哈希表的一个有趣的应用可以用来格式化文本输出。Powershell许多命令的输出结果都是以表格的形式,当然可以使用Format-Table自定义表格格式,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
PS C:Powershell> Dir | Format-Table

Directory: C:Powershell

Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 2011/11/23 17:25 ABC
d---- 2011/11/29 18:21 myscript

PS C:Powershell> Dir | Format-Table FullName,Mode

FullName Mode
-------- ----
C:PowershellABC d----
C:Powershellmyscript d----
C:Powershella.html

  上述的命令只能限制表格输出那些列,隐藏那些列。但是对于列的宽度,列标题无能为力,但是有了哈希表就可以实现更多自定义了。

表格的每一个列包含四个属性:
Expression:绑定的表达式
Width:列宽度
Label:列标题
Alignment:列的对齐方式

1
2
3
4
5
6
7
8
9
PS C:Powershell> $column1 = @{expression="Name"; width=30;label="filename"; alignment="left"}
PS C:Powershell> $column2 = @{expression="LastWriteTime"; width=40;label="last modification"; alignment="right"}
PS C:Powershell> ls | Format-Table $column1, $column2

filename last modification
-------- -----------------
ABC 2011/11/23 17:25:53
myscript 2011/11/29 18:21:28
a.html 2011/11/24 18:30:13
欢迎打赏,谢谢
------ 本文结束------
0%