简体   繁体   English

PowerShell 中的“$myvariable =”和 Set-Variable 有什么不同?

[英]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 .结果是218450x5555

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

    • additionally, it shows that it is a number when you ask for its type with .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" )中的字符串。

      • However, the original string representation can be retrieved with $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-VariableNew-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.

相关问题 如何在PowerShell中使用Set-Variable声明全局变量? - How to declare global variable using Set-Variable in PowerShell? Powershell Set-Variable 重置变量而不是更新它 - Powershell Set-Variable resets Variable instead of updating it Azure DevOps 条件无法评估 Powershell 设置变量 - Azure DevOps conditional can't evaluate Powershell set-variable 集变量Powershell。 如何将变量链接到exe文件? - Set-Variable powershell. How do I link a variable to an exe file? 在 Powershell 中设置变量不覆盖脚本参数? 尝试使用 JSON 读取 JSON 并覆盖脚本参数 - In Powershell set-variable not overriding Script Parameters? Trying to read JSON and override script parameters using JSON Set-Variable foo -Scope Global -Value“bar”和$ global:foo =“bar”之间的区别 - Difference between Set-Variable foo -Scope Global -Value “bar” and $global:foo = “bar” 无法使用Set-Variable设置变量的Description属性 - Unable to set Description property of a variable using Set-Variable 在循环中使用Set-Variable设置子值(例如$ Myvar.item.value)的问题 - Issues using Set-Variable to set sub values (ex. $Myvar.item.value) in loop Powershell的New-Alias和Set-Alias cmdlet之间有什么区别? - What's the difference between Powershell's New-Alias and Set-Alias cmdlets? 将switch语句中的多个值并将结果设置为变量的powershell语法是什么? - What's the powershell syntax for multiple values in a switch statement and set result to variable?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM