【问题标题】:Is there a way to wordwrap results of a Powershell cmdlet?有没有办法对 Powershell cmdlet 的结果进行自动换行?
【发布时间】:2010-11-06 18:38:09
【问题描述】:

简单(可能很愚蠢)的问题。我是 Powershell 新手,主要使用它来实例化托管库,因此当我需要使用其中的成员时,我不必编写小应用程序。其中一些库很旧,并且具有带有长而痛苦的签名的方法。在用 new-object 实例化后使用 get-member,我经常遇到这样令人沮丧的结果:

PS> $object | get-member MethodWithLongSignature

TypeName: SomeLib.SomeObject

Name                      MemberType Definition
----                      ---------- ----------
MethodWithLongSignature   Method     System.Void MethodWithLongSignature(string param1, int param2, string param3, string param4, stri....

有没有办法包装get-member的结果?或者,是否有一个 get-member 开关会以不换行的方式产生结果?

【问题讨论】:

    标签: powershell


    【解决方案1】:

    表格结构中的输出会自动格式化以适合屏幕的宽度,如有必要,会在处理过程中截断长值。

    将结果输入format-list 命令以获得详细的垂直格式结果。

    PS> $object | get-member MethodWithLongSignature | format-list
    

    【讨论】:

    • 为什么这不起作用$object | get-childitem env:path | format-list
    • 为什么,试试 Get-ChildItem Env:Path |格式列表。很难弄清楚这一点。我只想知道,我应该把练习脚本放在哪里。为了大家方便,ms how-to 文章(How to Write and Run Scripts...)并没有提到这一点。
    【解决方案2】:

    Format-Table 有一个 -Wrap 开关来换行最后一列。由于 Get-Member 输出的最后一列已经很大,这将产生可读的结果。

    另一个选项是 Format-Wide(但它不换行,因此您受限于控制台宽度):

    Get-Process | Get-Member | Format-Wide Definition -Column 1
    

    【讨论】:

      【解决方案3】:

      你也可以试试Format-Table -wrap。例如:

      (get-process -id 3104).startinfo.EnvironmentVariables | Format-Table -wrap
      

      【讨论】:

        【解决方案4】:

        我找不到允许自动换行到任意宽度的内置内容,所以我写了一个 - 有点冗长,但在这里:

        function wrapText( $text, $width=80 )
        {
            $words = $text -split "\s+"
            $col = 0
            foreach ( $word in $words )
            {
                $col += $word.Length + 1
                if ( $col -gt $width )
                {
                    Write-Host ""
                    $col = $word.Length + 1
                }
                Write-Host -NoNewline "$word "
            }
        }
        

        【讨论】:

        • 我认为您的意思是在 if 循环内将 $col 重置为零,是吗?
        【解决方案5】:

        基于 Leo 的回答,我决定创建一个 word-wrap cmdlet。

        <#
        .SYNOPSIS
        wraps a string or an array of strings at the console width without breaking within a word
        .PARAMETER chunk
        a string or an array of strings
        .EXAMPLE
        word-wrap -chunk $string
        .EXAMPLE
        $string | word-wrap
        #>
        function word-wrap {
            [CmdletBinding()]
            Param(
                [parameter(Mandatory=1,ValueFromPipeline=1,ValueFromPipelineByPropertyName=1)]
                [Object[]]$chunk
            )
            PROCESS {
                $Lines = @()
                foreach ($line in $chunk) {
                    $str = ''
                    $counter = 0
                    $line -split '\s+' | %{
                        $counter += $_.Length + 1
                        if ($counter -gt $Host.UI.RawUI.BufferSize.Width) {
                            $Lines += ,$str.trim()
                            $str = ''
                            $counter = $_.Length + 1
                        }
                        $str = "$str$_ "
                    }
                    $Lines += ,$str.trim()
                }
                $Lines
            }
        }
        

        它既可以通过将字符串或字符串数​​组作为函数参数传递,也可以在管道上工作。例子:

        $str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " * 5
        
        word-wrap $str
        $str | word-wrap
        get-content txtfile.txt | ?{ $_ } | sort | word-wrap
        

        函数顶部的元数据注释块允许get-help word-wrap 显示一些有用的信息。 See this page 了解有关定义管道 cmdlet 的更多信息。

        【讨论】:

        • 为了更惯用,应该是 Wrap-Word。
        【解决方案6】:

        作为替代方案,您可以使用“PowerShell Tools for Visual Studio 2015”扩展在 VS 2015 中运行您的 powershell 脚本。

        https://marketplace.visualstudio.com/items?itemName=AdamRDriscoll.PowerShellToolsforVisualStudio2015&showReviewDialog=true

        这为您提供了所有 VS 编辑器功能、自动换行、调试、智能感知等。

        【讨论】:

          【解决方案7】:

          我喜欢 @Leo 和 @rojo 的答案背后的意图,但拆分行不适合大量文本,并且状态机(或者更好的是,一个易于编程的......像正则表达式)会更有效率。

          除了编写我自己的复杂解决方案之外,我还保证了它的复杂性,因为它在原始字符串中保留换行符,甚至允许您对某些字符强制换行

          Wrap -Length 30 -Force '.' "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
          

          在这里,我尝试打断大约 30 个字符,找到最近的空格,但也强制在句号处打断,忽略单词中的句点,并确保不要打断因句号而已经中断的行。

          Lorem Ipsum is simply dummy
          text of the printing and
          typesetting industry.
          Lorem Ipsum has been the
          industry's standard dummy text
          ever since the 1500s, when an
          unknown printer took a galley
          of type and scrambled it to
          make a type specimen book.
          It has survived not only five
          centuries, but also the leap
          into electronic typesetting,
          remaining essentially
          unchanged.
          It was popularised in the
          1960s with the release of
          Letraset sheets containing
          Lorem Ipsum passages, and more
          recently with desktop
          publishing software like Aldus
          PageMaker including versions
          of Lorem Ipsum.
          

          这是函数本身,但请注意,您需要此答案底部的内容来生成正则表达式(我把它放在更高的位置,以便您可以阅读参数)

          Function Wrap {
              Param (
                  [int]$Length=80,
                  [int]$Step=5,
                  [char[]]$Force,
                  [parameter(Position=0)][string]$Text
              )
              $key="$Length $Step $Force"
              $wrap=$_WRAP[$key]
              if (!$wrap) {
                  $wrap=$_WRAP[$key]=_Wrap `
                      -Length $Length `
                      -Step $Step `
                      -Force ($Force -join '') `
                  | Concat -Join '|' -Wrap '(',')(?:[^\n\r\S])+'
              }
              return $Text -replace $wrap,$_WRAP['']
          }
          

          这里有一些更有意义的东西来展示它的多功能性。
          不要担心脚本的其余部分,它是 colours/backgroundsemailingGridView
          它基本上是在做一堆 ping、tcp 检查和 http 请求,并将错误消息放入 info 属性中:

                  $_.info=(
                      $style.bf.yellow, `
                      (Wrap -Length 55 -Force ':.' $_.info), `
                      $colour `
                  | Concat)
          

          您将需要上面定义的以下这些实用函数Wrap

          Function Concat {
              Param ([switch]$Newlines, $Wrap, $Begin='', $End='', $Join='')
              Begin {
                  if ($Newlines) {
                      $Join=[System.Environment]::NewLine
                  }
                  $output=[System.Text.StringBuilder]::new()
                  $deliniate=$False
          
                  if (!$Wrap) {
                      $output.Append($Begin) | Out-Null
                  }
                  elseif ($Wrap -is [string]) {
                      $output.Append(($End=$Wrap)) | Out-Null
                  }
                  else {
                      $output.Append($Wrap[0]) | Out-Null
                      $End=$Wrap[1]
                  }
              }
              Process {
                  if (!($_=[string]$_).length) {
                  }
                  elseif ($deliniate) {
                      $output.Append($deliniate) | Out-Null
                      $output.Append($_) | Out-Null
                  }
                  else {
                      $deliniate=$Join
                      $output.Append($_) | Out-Null
                  }
              }
              End {
                  $output.Append($End).ToString()
              }
          }
          
          $_WRAP=@{''="`$1$([System.Environment]::NewLine)"}
          Function _Wrap {
              Param ($Length, $Step, $Force)
          
              $wrap=$Force -join '' -replace '\\|]|-','\$0'
              $chars="^\n\r$wrap"
              $preExtra="[$chars\S]*"
              $postExtra="[^\s$wrap]"
          
              $chars="[$chars]"
              $postChars="$preExtra$postExtra"
              if ($wrap) {
                  $wrap="[$wrap]"
                  $wrap
                  $wrap="$wrap(?=\S)"
                  $chars="$chars|$wrap"
                  $postChars="$postChars|$preExtra$wrap"
              }
          
              for (
                  ($extra=0),($next=$NULL),($prev=$NULL);
                  ($next=$Length - $Step) -gt 0 -and ($prev=$extra + $Step);
                  ($Length=$next),($extra=$prev)
              ) {
                  "(?:$chars){$next,$Length}(?=(?:$postChars){$extra,$prev})"
              }
          }
          

          【讨论】:

            【解决方案8】:
            PS> $object | get-member MethodWithLongSignature | select -ExpandProperty Definition
            

            例如:

            PS>gci | gm EnumerateFiles
            TypeName: System.IO.DirectoryInfo
            
            Name           MemberType Definition
            ----           ---------- ----------
            EnumerateFiles Method     System.Collections.Generic.IEnumerable[System.IO.FileInfo] EnumerateFiles(), System.Collections.Generic.IEnumerable[System.IO.FileInfo] EnumerateFiles(string searchPattern), System.Collections.Generic.IEnume...
            

            相比:

            PS>gci | gm EnumerateFiles | select -ExpandProperty definition
            
                System.Collections.Generic.IEnumerable[System.IO.FileInfo] EnumerateFiles(), System.Collections.Generic.IEnumerable[System.IO.FileInfo] EnumerateFiles(string searchPattern), System.Collections.Generic.IEnumerable[System.IO.FileInfo] EnumerateFiles(string searchPattern, System.IO.SearchOption searchOption)
            

            具有讽刺意味的是,我的 PS 行包含了输出,但 SO 上的代码格式似乎没有。但是,您可以清楚地看到第一个示例中的 ... 截断。

            这是我的 shell 中包装输出的图片:

            ExpandProperty 在您想要输出特定属性时很有用。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-02-01
              • 1970-01-01
              • 2013-11-16
              • 1970-01-01
              • 2023-03-31
              • 2015-03-26
              相关资源
              最近更新 更多