在下面的代码中,为什么name1的[int]类型赋值被忽略,实际上被视为值的一部分?臭虫?
$name1 = 4
$name2 = 4
$name3 = 4
$myObject = New-Object System.Object
$myObject | Add-Member -type NoteProperty -name name1 -Value [int]$name1
$myObject | Add-Member -type NoteProperty -name name2 -Value $($name2 -as [int])
$myObject | Add-Member -type NoteProperty -name name3 -Value $([int]$name3)
$myObject
输出:
name1 name2 name3
----- ----- -----
[int]4 4 4
Powershell版本:
get-host | select-object version
Version
-------
5.1.19041.1023
3条答案
按热度按时间niwlg2el1#
在现有的答案中有很好的信息,但让我尝试一个系统的概述:
tl;dr
为了传递 * 表达式的输出(例如
[int] $name1
或$env:HOME + '\foo'
)、或(嵌套) 命令**(例如Get-Date -Format yyyy
)作为 * 命令的 * 参数 *(例如Add-Member
),将其括在(...)
中,分组运算符:相比之下,
$(...)
,子表达式运算符在这种情况下通常 * 不 * 需要,并且它的使用可能会产生副作用-参见this answer。"..."
),您只需要$(...)
包含一个 *language语句 *(例如if
语句或foreach
循环)或 * 多个 * 语句(用;
分隔的命令,表达式和语言语句的任何混合)。PowerShell解析方式:
PowerShell有*两种 * 基本解析模式:
参数 * mode,工作方式类似 * shell***。
.ps1
脚本的路径名称),后跟 * 参数*的 * 空格分隔列表 *,其中字符串可以 * 不加引号 *[1],由文字部分和变量引用混合组成的参数 * 通常 * 被视为可扩展字符串(就好像它们被封闭在"..."
中一样)。expression mode,其工作方式类似于 * 编程语言,其中字符串必须被引用,并且可以使用 * 运算符 * 和 * 语言语句 ,例如赋值,
foreach
和while
循环, 转换 *。概念性的
about_Parsing
提供了对这些模式的介绍;简而言之,*它是给定上下文中的 * 第一个令牌 ,它决定应用哪种模式。一个给定的语句可以由以任何一种模式解析的部分组成,这确实是上面发生的事情:
Add-Member
)开头,因此将以 argument 模式进行解析。(...)
强制一个新的解析上下文,在本例中([int] $name1
)是以 expression 模式解析的,因为是从[
开始的)。元字符 (具有特殊语法意义的字符) 在不同的解析模式下有所不同:
[
和=
仅在 expression 模式下是特殊的,而在 argument 模式下则不是,在 * argument* 模式下,它们是 * 逐字 * 使用的。@
后跟一个变量 name 只有在 argument 模式下才是特殊的,在这种模式下,它用于参数splatting。因此,复合参数
[int]$name1
被视为 * 可扩展字符串 *,并导致逐字字符串[int]4
。**某些表达式在用作命令参数时不需要 * 包含在
(...)
**中(假设为$var = 'Foo'
):Write-Output $var
或Write-Output $env:OS
)Write-Output $var.Length
)Write-Output $var.ToUpper()
)请注意,这些参数是以其原始数据类型传递的,而不是字符串化的(尽管字符串化可以由接收命令执行)。
陷阱:
"..."
来抑制属性访问解释,并使变量引用后面的.
被逐字解释(例如Write-Output "$var.txt"
,以便获得逐字foo.txt
)。$(...)
作为复合参数的一部分 * 而没有 * 显式的"..."
引号,如果$(...)
子表达式 * 开始 * 参数,该参数将被分解为 * 多个 * 参数(例如,Write-Output $('a' + 'b')/c
传递 * 两个 * 参数,逐字ab
和/c
,而Write-Output c/$('a' + 'b')
只传递一个,逐字c/ab
)。Write-Output One"$var"'$Two'
按预期工作并产生逐字OneFoo$Two
,但Write-Output 'One'"$var"'$Two'
作为 * 三个 * 参数传递,逐字One
,Foo
和$Two
)。简而言之:
"..."
之外使用$(...)
,并避免在单个字符串参数中混合使用引号样式;或者使用(单个)"..."
字符串(例如,Write-Output "$(Split-Path $PROFILE)/foo.txt"
或)或表达式中的字符串串联(Write-Output ('One' + $var + '$Two')
[1]假设它们既不包含空格,也不包含任何PowerShell的元字符(请参阅this answer)。而引号通常采取的形式是将整个参数括在单引号或双引号中,视情况而定(例如
'foo bar'
,"foo $var"
),也可以用引号(转义)* 单个 * 字符(例如foo
bar`),使用反引号(```),PowerShell的转义字符。vyu0f0g12#
关于
about_Parsing
help file:参数模式
解析时,PowerShell首先会将输入解释为表达式。但是当遇到命令调用时,解析将以参数模式继续。
参数模式设计用于分析shell环境中命令的参数和参数。除非使用以下语法之一,否则所有输入都被视为可扩展字符串:
...
您可以将代码包含在子表达式(
$(...)
)中,以避免PowerShell将[int]$name1
视为可扩展字符串,正如您已经发现的那样:-)ax6ht2ek3#
这是故意的。在将表达式传递给函数之前,需要用圆括号括起来,以便计算表达式。
如果你尝试在那里放置一个函数调用,例如:
返回为:
Write-Host [string]2
返回[string]2
而不是2