【问题标题】:Printing useful variable values in powershell (in particular, involving $null/empty string)在 powershell 中打印有用的变量值(特别是涉及 $null/空字符串)
【发布时间】:2017-10-19 15:59:38
【问题描述】:

如果我有:

$a=$null
$b=''
$c=@($null,$null)
$d='foo'
write-host $a
write-host $b
write-host $c
write-host $d

输出是

foo

我真的很希望能够轻松获得显示变量值的输出,例如,

$Null
''
@($Null,$Null)
'foo'

我可以编写一个函数来执行此操作,但我猜测/希望我缺少一些内置的东西。有没有,或者每个人都只是为这样的事情推出自己的功能?

目前我想出的最快的方法是在打印之前通过 ConvertTo-Json 运行一个值。它不能处理普通的 $null,但它很好地向我展示了其他值。

【问题讨论】:

  • if ( $x -eq $null ) { '$null' } elseif ( $x -eq "") { '""' } else { $x }
  • 是的,我知道我可以写点东西。但后来我必须修复/扩展/维护它。例如,上面的 sn-p 将为 @($null,$null) 打印 $null。

标签: powershell


【解决方案1】:

您要查找的内容类似于Ruby's .inspect method。这是我在 Ruby 中一直喜欢的东西,而在 PowerShell/.Net 中却很怀念。

不幸的是,据我所知没有这样的事情,所以你不得不自己动手。

您在 .Net 中最接近的是 .ToString() 方法,它至少只显示对象类型(它继承自 [System.Object])。

因此,您将不得不自己进行一些检查。让我们谈谈边缘情况检查。

数组

您应该首先检查您是否正在处理数组,因为 PowerShell 经常为您展开数组并合并对象,因此如果您开始进行其他检查,您可能无法正确处理它们。

检查你是否有一个数组:

$obj -is [array]

1 -is [array]  # false
1,2,3 -is [array]  # true
,1 -is [array]  #true

对于数组,如果您还想正确序列化其元素,则必须对其进行迭代。这基本上是您的函数最终会递归的部分。

function Format-MyObject {
param(
    $obj
)

    if ($obj -is [array]) {
        # initial array display, like "@(" or "["
        foreach ($o in $obj) {
            Format-MyObject $obj
        }
        # closing array display, like ")" or "]"
    }
}

空值

只需检查它是否等于$null

$obj -eq $null

字符串

您可以先使用-is [string] 测试您是否正在处理字符串。

对于空字符串,您可以将字符串与空字符串进行比较,或者更好地与[string]::Empty 进行比较。您也可以使用.IsNullOrEmpty() 方法,但前提是您已经排除了空值(或检查了它确实是一个字符串):

if ($obj -is [string) {
    # pick one

    if ([string]::IsNullOrEmpty($obj)) {
        # display empty string
    }

    if ($obj -eq [string]::Empty) {
        # display empty string
    }

    if ($obj -eq "") { # this has no advantage over the previous test
        # display empty string
    }
}

另类

您可以使用内置的 XML 序列化,然后解析 XML 以从中获取值。

这是有效的(我不会在 SO 答案中这样做),但它消除了许多潜在的人为错误,并且在某种程度上为该方法提供了未来证明。

基本思路:

$serialized = [System.Management.Automation.PSSerializer]::Serialize($obj) -as [xml]

现在,使用内置的 XML 方法对其进行解析并提取出您需要的内容。您仍然需要将一些内容转换为其他内容以显示您想要的方式(例如解释 <nil /> 和类型列表以正确显示数组等),但我喜欢将实际序列化留给官方组件。

快速示例:

[System.Management.Automation.PSSerializer]::Serialize(@(
    $null,
    1,
    'string',
    @(
        'start of nested array',
        $null,
        '2 empty strings next',
        '', 
        ([string]::Empty)
    )
)
)

还有输出:

<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
  <Obj RefId="0">
    <TN RefId="0">
      <T>System.Object[]</T>
      <T>System.Array</T>
      <T>System.Object</T>
    </TN>
    <LST>
      <Nil />
      <I32>1</I32>
      <S>string</S>
      <Obj RefId="1">
        <TNRef RefId="0" />
        <LST>
          <S>start of nested array</S>
          <Nil />
          <S>2 empty strings next</S>
          <S></S>
          <S></S>
        </LST>
      </Obj>
    </LST>
  </Obj>
</Objs>

【讨论】:

  • 不错的答案;感谢您指出 PSSerializer。这似乎是最通用和面向未来的,因为我认为这是 PS 用于所有数据传输的方法,即使它有点冗长。在此和 ConvertTo-Json -Depth 100 之间,用于一般的普通数据类型和某些集合,我想我现在有几个不错的选择。
【解决方案2】:

我分享了两个函数,它们比通常更进一步地显示 PowerShell 值(包括空的 $Null's、空数组等):

  • 将 PowerShell 对象序列化为 PowerShell Object Notation (PSON) 最终目标是能够扭转一切 标准命令Invoke-Expression 并将其解析回 PowerShell 对象。

  • 另一个是我用的ConvertTo-Text(别名CText)函数 我的Log-Entry framework。注意 具体行:我写的Log "Several examples that usually aren't displayed by Write-Host:" $NotSet @() @(@()) @(@(), @()) @($Null) 在示例中。


Function Global:ConvertTo-Text1([Alias("Value")]$O, [Int]$Depth = 9, [Switch]$Type, [Switch]$Expand, [Int]$Strip = -1, [String]$Prefix, [Int]$i) {
    Function Iterate($Value, [String]$Prefix, [Int]$i = $i + 1) {ConvertTo-Text $Value -Depth:$Depth -Strip:$Strip -Type:$Type -Expand:$Expand -Prefix:$Prefix -i:$i}
    $NewLine, $Space = If ($Expand) {"`r`n", ("`t" * $i)} Else{"", ""}
    If ($O -eq $Null) {$V = '$Null'} Else {
        $V = If ($O -is "Boolean")  {"`$$O"}
        ElseIf ($O -is "String") {If ($Strip -ge 0) {'"' + (($O -Replace "[\s]+", " ") -Replace "(?<=[\s\S]{$Strip})[\s\S]+", "...") + '"'} Else {"""$O"""}}
        ElseIf ($O -is "DateTime") {$O.ToString("yyyy-MM-dd HH:mm:ss")} 
        ElseIf ($O -is "ValueType" -or ($O.Value.GetTypeCode -and $O.ToString.OverloadDefinitions)) {$O.ToString()}
        ElseIf ($O -is "Xml") {(@(Select-XML -XML $O *) -Join "$NewLine$Space") + $NewLine}
        ElseIf ($i -gt $Depth) {$Type = $True; "..."}
        ElseIf ($O -is "Array") {"@(", @(&{For ($_ = 0; $_ -lt $O.Count; $_++) {Iterate $O[$_]}}), ")"}
        ElseIf ($O.GetEnumerator.OverloadDefinitions) {"@{", (@(ForEach($_ in $O.Keys) {Iterate $O.$_ "$_ = "}) -Join "; "), "}"}
        ElseIf ($O.PSObject.Properties -and !$O.value.GetTypeCode) {"{", (@(ForEach($_ in $O.PSObject.Properties | Select -Exp Name) {Iterate $O.$_ "$_`: "}) -Join "; "), "}"}
        Else {$Type = $True; "?"}}
    If ($Type) {$Prefix += "[" + $(Try {$O.GetType()} Catch {$Error.Remove($Error[0]); "$Var.PSTypeNames[0]"}).ToString().Split(".")[-1] + "]"}
    "$Space$Prefix" + $(If ($V -is "Array") {$V[0] + $(If ($V[1]) {$NewLine + ($V[1] -Join ", $NewLine") + "$NewLine$Space"} Else {""}) + $V[2]} Else {$V})
}; Set-Alias CText ConvertTo-Text -Scope:Global -Description "Convert value to readable text"

转换为文本

ConvertTo-Text 函数(别名 CText)递归地将 PowerShell 对象转换为可读文本,其中包括哈希表、自定义对象和显示类型详细信息(例如 $Null 与空字符串)。

语法

ConvertTo-Text [<Object>] [[-Depth] <int>] [[-Strip] <int>] <string>] [-Expand] [-Type]

参数

&lt;Object&gt;
应转换为可读值的对象(位置 0)。

-⁠Depth &lt;int&gt;
显示嵌入对象的最大递归迭代次数。
ConvertTo-Text 的默认深度是 9

-Strip &lt;int&gt;
如果提供的值等于或大于0,则截断给定长度的字符串并删除多余的空白字符。设置-Strip -1 可防止截断和删除带有空格的字符。
ConvertTo-Text 的默认值为 -1

-Expand
将嵌入对象扩展到多行以提高可读性。

-Type
通过在对象前面添加[&lt;Type&gt;] 来明确显示对象的类型。

注意:参数$Prefix供内部使用。

示例

以下命令返回一个字符串,描述$var 变量所包含的对象:

ConvertTo-Text $Var

以下命令返回一个包含示例中所示哈希表的字符串(而不是System.Collections.DictionaryEntry...):

ConvertTo-Text @{one = 1; two = 2; three = 3}

以下命令显示 PowerShell 通常不显示的值(例如 $Null):

ConvertTo-Text @{Null = $Null; EmptyString = ""; EmptyArray = @(); ArrayWithNull = @($Null); DoubleEmptyArray = @(@(), @())} -Expand

以下命令返回一个字符串,显示 WinNT User 对象的深度最高为 5 级,并将嵌入的对象扩展为多行:

ConvertTo-Text ([ADSI]"WinNT://./$Env:Username") -Depth 5 -Expand

【讨论】:

  • 这很酷。我建议你稍微清理一下,用它制作一个模块,放在 GitHub 上,然后将它发布到 PowerShell Gallery 以便它可以作为一个包使用。
【解决方案3】:

适用于某些数据类型的快速自滚动选项。

function Format-MyObject {
param(
    $obj
)
    #equality comparison order is important due to array -eq overloading
    if ($null -eq $obj)
    {
        return 'null'
    }
    #Specify depth because the default is 2, because powershell
    return ConvertTo-Json -Depth 100 $obj 
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-05
    • 1970-01-01
    • 2016-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多