[英]What's different between "$myvariable =" and Set-Variable in PowerShell?
When I study PowerShell scripting language, I try to use "Write-Output" command to display variable.当我学习 PowerShell 脚本语言时,我尝试使用“Write-Output”命令来显示变量。
I use a different method to create variables.我使用不同的方法来创建变量。
Example:例子:
$myvariable = 0x5555
Set-Variable -Name myvariable2 -Value 0x5555
The data type of these two variables is Int32.这两个变量的数据类型是 Int32。
When I use the command as below,当我使用如下命令时,
Write-Output $myvariable $myvariable2
the result is 21845
and 0x5555
.结果是21845
和0x5555
。
What's different between these two variables?这两个变量有什么不同?
How can I display format result like printf %d %x
?如何显示格式结果,如printf %d %x
?
The first question is already answered by @PetSerAl in the comments. @PetSerAl 在评论中已经回答了第一个问题。 Your second question:你的第二个问题:
How can I display format result like printf %d %x如何显示格式结果,如 printf %d %x
Use PowerShell string formatting to obtain the desired results.使用 PowerShell字符串格式来获得所需的结果。
PetSerAl , as many times before, has given the crucial pointer in a comment (and later helped improve this answer): PetSerAl和以前一样多次在评论中给出了关键指针(后来帮助改进了这个答案):
Written as of PowerShell Core 6.2.0.从 PowerShell Core 6.2.0 开始编写。
PowerShell parses an unquoted literal argument that looks like a number as a number and wraps it in a "half-transparent" [psobject]
instance , whose purpose is to also preserve the exact argument as specified as a string . PowerShell 将看起来像数字的不带引号的文字参数解析为数字,并将其包装在“半透明” [psobject]
实例中,其目的也是保留指定为字符串的确切参数。
By half-transparent I mean that the resulting $myVariable2
:半透明是指生成的$myVariable2
:
primarily is a number - a regular (unwrapped) [int]
instance - for the purpose of calculations ;主要是一个数字- 一个常规(展开的) [int]
实例 - 用于计算; eg, $myVariable2 + 1
correctly returns 21846
例如, $myVariable2 + 1
正确返回21846
.GetType()
or via the Get-Member
cmdlet;此外,当您使用.GetType()
或通过Get-Member
cmdlet 询问其类型时,它会显示它是一个数字; in other words: in this case PowerShell pretends that the wrapper isn't there (see below for a workaround).换句话说:在这种情况下,PowerShell 假装包装器不存在(请参阅下面的解决方法)。situationally behaves like a string - returning the original argument literal exactly as specified - in the context of:在情况下表现得像一个字符串- 完全按照指定返回原始参数文字 - 在以下上下文中:
output formatting , both when printing directly to the console and generally with Out-*
cmdlets such as Out-File
(but not Set-Content
) and Format-*
cmdlets.输出格式,直接打印到控制台时,通常使用Out-*
cmdlet,例如Out-File
(但不是Set-Content
)和Format-*
cmdlet。
string formatting with -f
, PowerShell's format operator (which is based on .NET's String.Format()
method ; eg, 'The answer is {0}' -f 42
is equivalent to [string]::Format('The answer is {0}', 42)
).使用 -f 格式化字符串-f
PowerShell 的格式运算符(基于 .NET 的String.Format()
方法;例如, 'The answer is {0}' -f 42
相当于[string]::Format('The answer is {0}', 42)
)。
Surprisingly, it does not behave like a string inside an expandable string ( "$myVariable2"
) and when you call the .ToString()
method ( $myVariable2.ToString()
) and (therefore also) with Set-Content
.令人惊讶的是,当您调用.ToString()
方法( $myVariable2.ToString()
)和(因此也)使用Set-Content
时,它的行为不像可扩展字符串( "$myVariable2"
)中的字符串。
$myVariable2.psobject.ToString()
但是,可以使用$myVariable2.psobject.ToString()
检索原始字符串表示形式Note that specifying number literals as command arguments is inherently ambiguous , because even string arguments generally don't need quoting (unless they contain special characters), so that, for instance, an argument such as 1.0
could be interpreted as a version string or as a floating-point number .请注意,将数字文字指定为命令参数本质上是不明确的,因为即使是字符串参数通常也不需要引用(除非它们包含特殊字符),因此,例如,诸如1.0
之类的参数可以解释为版本字符串或一个浮点数。
PowerShell's approach to resolving the ambiguity is to parse such a token as a number , which, however, situationally acts as a string [1] , as shown above. PowerShell 解决歧义的方法是将这样的标记解析为 number ,但是,它在情境中充当字符串[1] ,如上所示。
The ambiguity can be avoided altogether by typing parameters so as to indicate whether an argument bound to it is a string or a number.可以通过键入参数来完全避免歧义,以指示绑定到它的参数是字符串还是数字。
However, the -Value
parameter of the Set-Variable
and New-Variable
cmdlets is - of necessity - [object]
typed, because it must be able to accept values of any type, and these cmdlets don't have a parameter that would let you indicate the intended data type.但是, Set-Variable
和New-Variable
cmdlet 的-Value
参数必须是[object]
类型的,因为它必须能够接受任何类型的值,并且这些 cmdlet 没有可以让您指明预期的数据类型。
The solution is to force the -Value
argument to be treated as the result of an expression rather than as an unquoted literal argument , by enclosing it in (...)
:解决方案是通过将-Value
参数包含在(...)
中来强制将其视为表达式的结果,而不是作为未引用的文字参数:
# Due to enclosing in (...), the value that is stored in $myvariable2
# is *not* wrapped in [psobject] and therefore behaves the same as
# $myvariable = 0x55555
Set-Variable -Name myvariable2 -Value (0x5555)
Conversely, if you don't apply the above solution, you have two choices for unwrapping $myvariable2
's value on demand :相反,如果您不应用上述解决方案,您有两种选择来按需解$myvariable2
的值:
# OK: $myvariable isn't wrapped in [psobject], so formatting it as a
# hex. number works as expected:
PS> 'hex: 0x{0:x}' -f $myvariable
hex: 0x5555 # OK: Literal '0x' followed by hex. representation of the [int]
# !! Does NOT work as expected, because $myvariable2 is treated as a *string*
# !! That is, {0:x} is effectively treated as just {0}, and the string
# !! representation stored in the [psobject] wrapper is used as-is.
PS> 'hex: 0x{0:x}' -f $myvariable2
hex: 0x0x5555 # !! Note the extra '0x'
# Workaround 1: Use a *cast* (with the same type) to force creation of
# a new, *unwrapped* [int] instance:
PS> 'hex: 0x{0:x}' -f [int] $myvariable2
hex: 0x5555 # OK
# Workaround 2: Access the *wrapped* object via .psobject.BaseObject.
# The result is an [int] that behaves as expected.
PS> 'hex: 0x{0:x}' -f $myvariable2.psobject.BaseObject
hex: 0x5555 # OK
Note: That -f
, the format operator , unexpectedly treats a [psobject]
-wrapped number as a string is the subject of GitHub issue #17199 ;注意: 格式运算符-f
意外地将[psobject]
包裹的数字视为字符串,这是GitHub 问题 #17199的主题; sadly, the behavior was declared to be by design.可悲的是,这种行为被宣布为设计使然。
Detecting a [psobject]
-wrapped value:检测[psobject]
包装的值:
The simplest solution is to use -is [psobject]
:最简单的解决方案是使用-is [psobject]
:
PS> $myvariable -is [psobject]
False # NO wrapper object
PS> $myvariable2 -is [psobject]
True # !! wrapper object
(PetSerAl offers the following, less obvious alternative: [Type]::GetTypeArray((, $myvariable2))
, which bypasses PowerShell's hiding-of-the-wrapper trickery.) (PetSerAl 提供了以下不太明显的替代方案: [Type]::GetTypeArray((, $myvariable2))
,它绕过了 PowerShell 的隐藏包装技巧。)
[1] Preserving the input string representation in implicitly typed numbers passed as command arguments : [1]在作为命令参数传递的隐式类型数字中保留输入字符串表示:
Unlike traditional shells, PowerShell uses rich types, so that an argument literal such as 01.2
is instantly parsed as a number - a [double]
in this case, and if it were used as-is, it would result in a different representation on output, because - once parsed as a number - default output formatting is applied on output (where the number must again be turned into a string ):与传统 shell 不同,PowerShell 使用丰富的类型,因此01.2
之类的参数文字会立即被解析为数字- 在这种情况下是[double]
,如果按原样使用,则会在输出中产生不同的表示形式,因为 - 一旦被解析为数字 - 默认输出格式将应用于输出(其中数字必须再次转换为字符串):
PS> 01.2
1.2 # !! representation differs (and is culture-sensitive)
However, the intent of the target command may ultimately be to treat the argument as a string and in that case you do not want the output representation to change.但是,目标命令的意图最终可能是将参数视为字符串,在这种情况下,您不希望输出表示发生变化。 (Note that while you can disambiguate numbers from strings by using quoting ( 01.2
vs. '01.2'
), this is not generally required in command arguments, the same way it isn't required in traditional shells.) (请注意,虽然您可以通过使用引号( 01.2
与'01.2'
)来消除字符串中的数字歧义,但在命令参数中通常不需要这样做,就像在传统 shell 中不需要一样。)
It is for that reason that a [psobject]
wrapper is used to capture the original string representation and use it on output.正是出于这个原因, [psobject]
包装器用于捕获原始字符串表示并将其用于输出。
Note: Arguably, a more consistent approach would have been to always treat unquoted literal arguments as strings , except when bound to explicitly numerically typed parameters in PowerShell commands.注意:可以说,更一致的方法是始终将不带引号的文字参数视为字符串,除非在 PowerShell 命令中绑定到显式数字类型参数。
This is a necessity for invoking external programs , to which arguments can only ever be passed as strings .这是调用外部程序的必要条件,参数只能作为字符串传递给这些程序。
That is, after initial parsing as a number, PowerShell must use the original string representation when building the command line (Windows) / passing the argument (Unix-like platforms) as part of the invocation of the external program.也就是说,在初始解析为数字之后,PowerShell 在构建命令行(Windows)/传递参数(类 Unix 平台)作为外部程序调用的一部分时必须使用原始字符串表示。
If it didn't do that, arguments could inadvertently be changed, as shown above (in the example above, the external program would receive string 1.2
instead of the originally passed 01.2
).如果不这样做,则可能会无意中更改参数,如上所示(在上面的示例中,外部程序将接收字符串1.2
而不是最初传递的01.2
)。
You can also demonstrate the behavior using PowerShell code, with an untyped parameter - though note that is generally preferable to explicitly type your parameters:您还可以使用带有未键入参数的 PowerShell 代码演示该行为 - 但请注意,通常最好显式键入参数:
PS> & { param($foo) $foo.GetType().Name; $foo } -foo 01.2
Double # parsed as number - a [double]
01.2 # !! original string representation, because $foo wasn't typed
$foo
is an untyped parameter, which means that the type that PowerShell inferred during initial parsing of literal 01.2
is used. $foo
是一个无类型参数,这意味着使用 PowerShell 在初始解析文字01.2
期间推断的类型。
Yet, given that the command (a script block ( { ... }
) in this case) didn't declare a parameter type for $foo
, the [psobject]
wrapper that is implicitly used shows the original string representation on output .然而,鉴于命令(在本例中为脚本块( { ... }
))没有为$foo
声明参数类型,隐式使用的[psobject]
包装器在 output 上显示原始字符串表示。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.