第18章|变量:把数据装进“盒子”的正确方式
第18章|变量:把数据装进“盒子”的正确方式(学习笔记 )
适用人群:PowerShell 新手到中级运维/开发,准备把“一次性命令”进化为可复用脚本的人。
目标:彻底理解变量、数组、双引号替换、转义、子表达式、类型约束,以及 v3+ 的自动展开(automatic unrolling)。
一、什么是变量?为何重要
- 变量 = 有名字的内存盒子:把字符串、数字、对象集合、XML 等放进去,随时再取出来复用。
- 弱声明、强能力:PowerShell 不要求预声明类型;但你可以显式指定类型来避免逻辑错误。
- 对象世界:在 PowerShell 里“一切皆对象”,就连字符串也是
System.String
。
二、最常用的变量基本功
1)创建与读取
$var = "SERVER-R2" # 赋值
$var # 读取
$var | Get-Member # 看看这是哪种对象(类型/方法/属性)
2)在命令里使用变量
Get-WmiObject Win32_ComputerSystem -ComputerName $var
3)变量命名建议
- 只用字母/数字/下划线,不要空格(真要用:
${My Var}
)。 - 名字要短而有义:
$computerName
、$services
。 - 关闭会话变量即消失(非持久)。
三、引号的“魔法”:单引号、双引号、转义、子表达式
1)单引号 vs 双引号
- 单引号:原样字符串,不做变量替换。
- 双引号:会做变量插值(替换)。
$computer = 'SERVER-R2'
$single = 'computer is $computer' # computer is $computer
$double = "computer is $computer" # computer is SERVER-R2
2)转义(重音符号 `)
- 取消特殊意义:`$ 输出美元符号本体
- 插入控制字符:`n 换行、`t 制表、`a 蜂鸣等
$phrase = "`$computer = $computer`nDone."
小贴士:用 Consolas 字体更容易区分 ` 与 ’ 。
3)子表达式 $()
- 当插值里包含属性/索引/复杂表达式时,必须用
$()
。
$services = Get-Service
$msg = "First service is $($services[0].Name)"
四、一次装很多:数组与集合
1)一次放入多个值
$computers = 'SRV1','SRV2','localhost' # 数组
$computers.Count # 3
$computers[0] # SRV1
$computers[-1] # localhost(倒数第一个)
2)批量访问(v3+ 自动展开 / automatic unrolling)
v3 起:访问集合的属性会隐式枚举。
$services = Get-Service
$services.Name # 输出每个服务的 Name(v3+)
等价于:
Get-Service | Select-Object -ExpandProperty Name
# 或
Get-Service | ForEach-Object { $_.Name }
3)批量调用方法(通用写法)
$computers = 'SRV1','SRV2'
$computers = $computers | ForEach-Object { $_.ToLower() } # 写回变量
五、强类型变量:让错误更早、更清楚
1)为什么要“上类型”
- 避免把“100”当字符串拼接十次而不是做乘法。
[int]$number = Read-Host "Enter a number" # 输入非数字会直接报错
$number = $number * 10
2)常见类型速查
[int]
:整数[single]
/[double]
:浮点[string]
:字符串[char]
:单个字符[xml]
:XML 文档(需有效 XML)[adsi]
:ADSI 查询句柄
3)重新指定类型
[int]$x = 5
# $x = "Hello" # 会报错(无法转为 Int32)
[string]$x = "Hello" # 重新声明为 string 后可赋值
六、变量相关 Cmdlet(知道即可)
Get-Variable / Set-Variable / New-Variable / Clear-Variable / Remove-Variable
- 绝大多数场景,直接用
$var = ...
语法就好;Cmdlet 更多用于作用域或元编程场景(参阅about_Scope
)。
七、最佳实践清单
- 命名简短有义,避免空格与晦涩缩写。
- 需要做算术或比较时,显式指定类型(如
[int]
)。 - 字符串插值:双引号 +
$()
,避免边界/索引解析错误。 - 集合访问优先用 v3+ 自动展开;跨版本脚本用
Select-Object -ExpandProperty
更通用。 - 修改数组元素请重新赋值或用
ForEach-Object
产生新集合再回写。 - 会话结束变量销毁;持久数据请落盘(CSV/Clixml/JSON)或存配置。
八、易错点速记
$
不是变量名的一部分;$var
的名字是var
。- 双引号里写
$services[0].Name
必须$()
包起来:$($services[0].Name)
。 - v1/v2 不支持自动展开;团队混用版本时要注意兼容写法。
Read-Host
得到的是字符串;需要数值请加类型约束或转换。
九、练习题(带参考答案)
Q1: 写一行,把两台机器的 Win32_BIOS
查询结果放入变量 $bios
。
A:
$bios = Invoke-Command { Get-WmiObject Win32_BIOS } -ComputerName localhost, $env:COMPUTERNAME
Q2: 展示 $bios
并导出为 CliXML(保留对象结构)。
A:
$bios
$bios | Export-Clixml -Path .\bios.xml
Q3: 读入一个数字并安全乘以 10。
A:
[int]$n = Read-Host "Enter a number"
$n * 10
Q4: 将所有服务名拼接到一句话里,且首个服务名单独强调(正确使用子表达式)。
A:
$svcs = Get-Service
$msg = "First is $($svcs[0].Name). All: $($svcs.Name -join ', ')"
$msg
Q5: 把数组 SRV1, SRV2, LOCALHOST
全部转小写并写回原变量。
A:
$computers = 'SRV1','SRV2','LOCALHOST'
$computers = $computers | ForEach-Object { $_.ToLower() }
十、常用片段收藏夹
# 1) 查看对象有哪些“能耐”
$var | Get-Member# 2) 读取服务列表并只取名字(v3+ 自动展开)
$services = Get-Service
$services.Name# 3) 双引号 + 子表达式:插值复杂表达式/索引
$msg = "Top service: $($services[0].Name)"# 4) 强类型输入,避免“100100100…”
[int]$count = Read-Host "Count?"
"*" * $count # 正常乘法语义# 5) 把集合做一次变换再写回
$computers = $computers | ForEach-Object { $_.Trim().ToLower() }# 6) 导入/导出强类型对象(持久化)
$services | Export-Clixml .\services.xml
$back = Import-Clixml .\services.xml
十一、延伸阅读
Get-Help about_Variables
Get-Help about_Quoting_Rules
(引号与转义)Get-Help about_Escape_Characters
Get-Help about_Scope
(变量作用域)Get-Help Export-Clixml / Import-Clixml
(对象持久化)