繁体   English   中英

PowerShell“少”工具

[英]PowerShell 'less' tool

不是围绕此的各种其他问题的重复(我审查了它们,但在我看到的问题中没有回答)。 那些其他问题围绕着Out-Host -Paging more (即使他们在问题标题中提到的less )。

为了关注这一特定点,有谁知道复制less功能的 PowerShell 方法,但在 Microsoft Windows 环境中? 即让我们能够向下和向上滚动文档(使用光标键逐行或使用 PgUp / PgDn 键逐页滚动)以查看帮助和其他文件(例如,我们可以执行Get-Help Get-ChildItem -Full | less )。

这将非常有用。 我不是在寻找适用于 Windows 的第 3 方可执行less工具(因为它不会启用管道等)(当然有很多)。 我相信 PSCX 中有这样的东西,但是每当我尝试安装它时,我都会看到很多冲突,而且我不确定使用-AllowClobber以防它破坏其他东西。 也许在那一点上,如果那里有一个less的东西,有没有人能够分离出该功能并独立于 PSCX 使用?

Get-Help Get-ChildItem -Full | less Get-Help Get-ChildItem -Full | less在类 Unix 平台上工作得很好,使用给定平台的less实用程序(通常为/usr/bin/less ) - 不需要额外的工作。

我不是在追求 3rd 方可执行的less工具(因为它不会启用管道等)

任何stdin (标准输入)读取并输出到stdout (标准输出)的外部程序(实用程序)根据定义是启用管道的,尽管总是仅针对文本:发送此类实用程序的数据被转换为文本,并返回数据这些实用程序被解释为文本。

Windows 上,默认情况下只有 - 功能受限 - more.com寻呼机可用- 见下文。

但是,可以在 Windows 上安装less

  • 如果您安装了WSL的 Linux 发行版,您可以简单地通过管道传输到wsl less 例如:

    • Get-Help Get-ChildItem | wsl less
    • 警告上一页/下一页从PowerShell中调用时貌似工作,但F(前锋)和B(后)提供相同的效用。
  • 否则,考虑安装less.exe Windows控制台应用程序(挑最近的文件夹中的版本),这是一部分GnuWin项目(安装程序需要管理员权限)。

    • 这为您提供了正常的PageUp / PageDown支持。

注意:Windows 还有一个less端口,它与其他实用程序捆绑在一起; 还没有亲自尝试过: UnxUtils

注意事项

  • less明显地期望 UTF-8 input ,而不管活动的 OEM 代码页如何,另外,如果[console]::OutputEncoding]设置为 UTF-8,则仅正确显示非 ASCII 字符。

    • 因此,必须将$OutputEncoding[console]::OutputEncoding]设置为 UTF-8 ( [Text.Utf8Encoding]::new() ) 才能正常显示非 ASCII 字符。 (在 PowerShell [Core] v6+ 中, $OutputEncoding默认为 UTF-8,但[console]::OutputEncoding]仍反映系统的 OEM 代码页。)

    • 有关如何使命令more /PowerShell 中的help功能使用less而不是more.com ,请参阅底部部分,通过自定义的more函数也确保使用 UTF-8 编码

  • GnuWin less.exe版本394 (在撰写本文时为less.exe版本,但于 2006-01-03 发布)有时会运行不稳定less.exe显示任何内容 开始一个新的会话会使问题消失。


- 不那么强大(没有双关语) - Windows 对应的lessmore ( more.com ) ,它通过 stdin / 管道或通过文件名参数接受文本。

值得注意的是, more.com似乎只支持向下翻页,有空格,不支持备份; 也就是说,您无法向后滚动 - 请参阅此处

PowerShell 自己的Out-Host -Paging也有同样的限制

  • Windows PowerShell提供了一个围绕more.com的内置包装函数,也命名为more (这意味着执行more执行该函数),它确保指定文件的内容以活动 OEM 代码页的编码输出,即more.com期待什么。

  • PowerShell [Core] 6+ 不再提供此包装器。

在这两个版本中,内置的help函数本身封装了Get-Help ,隐式地将后者的输出传递到more - 在 Windows PowerShell 中,默认情况下在 Windows 上的 PowerShell 6+ 中(在 Unix 上,它默认为less

在 PowerShell 6+ 中,您还可以通过将$env:PAGER变量设置为要调用以用于分页help输出的命令行来定义自定义分页器。

在 Windows PowerShell 中,您唯一的选择是替换/定义自定义的more函数(这也适用于 PowerShell 6+)。

换句话说:默认情况下,类似以下内容为您提供交互式分页输出:

help Get-ChildItem  # Effectively the same as: Get-Help Get-ChildItem | more

如果您在 Windows 上的可用空间less并且想要使用它而不是more

覆盖内置的 / 定义一个more函数如下(在你的$PROFILE文件中):

  • 通过 WSL 使用less
# Via WSL
function more { 
  $prevOe, $prevCoe = $OutputEncoding, [console]::OutputEncoding
  try {
    $OutputEncoding = [console]::OutputEncoding = [Text.Utf8Encoding]::new()
    $Input | wsl less
  }
  finally {
    $OutputEncoding, [console]::OutputEncoding = $prevOe, $prevCoe
  }
}

# If running PowerShell Core (v6+):
# Force the `help` function to use the custom function.
if ($IsCoreClr) { $env:PAGER = 'more' }
  • GnuWin less.exe使用:
# Via GnuWin (assuming the default installation location)
function more { 
  $prevOe, $prevCoe = $OutputEncoding, [console]::OutputEncoding
  try {
    $OutputEncoding = [console]::OutputEncoding = [Text.Utf8Encoding]::new()
    $Input | & 'C:\Program Files (x86)\GnuWin32\bin\less.exe'
  }
  finally {
    $OutputEncoding, [console]::OutputEncoding = $prevOe, $prevCoe
  }
}

# If running PowerShell Core (v6+):
# Force the `help` function to use the custom function.
if ($IsCoreClr) { $env:PAGER = 'more' }

注意:这使得more只接受管道输入,但扩展函数以接受文件名参数也不难。


如果满足以下条件,则有一个更简单的解决方案,由David Hatch提出:

  • 您已安装 GnuWin less.exe

  • 您不需要支持非 ASCII 字符。

  • 您这样做了,但是您的会话已经配置为将$OutputEncoding[console]::OutputEncoding为 UTF-8。 $OutputEncoding在 PowerShell [Core] v6+ 中默认为 UTF-8,但不是[console]::OutputEncoding] )。

    • 请参阅此答案,了解如何通过$PROFILE将 PowerShell 会话切换为一致地使用 UTF-8。

    • 请参阅此答案以了解如何在系统范围内配置 Windows 10 以使用代码页65001 == UTF-8,但请注意,在撰写本文时,该功能仍处于测试阶段,并且有副作用和限制; 值得注意的是,它使Windows PowerShell命令使用活动的 ANSI 代码页 ( Get-Content / Set-Content ) 然后默认为 UTF-8。

Windows PowerShell:

Set-Alias more 'C:\Program Files (x86)\GnuWin32\bin\less.exe'

PowerShell [核心] v6+:

$env:PAGER = 'C:\Program Files (x86)\GnuWin32\bin\less.exe'

我发现“少”和“多”可以正常工作。 经过查询,发现原因是安装了cygwin。



❯ Get-Command more

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Application     more.exe                                           

❯ Get-Command less                                                                                                                                                                                              CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Application     less.exe                                           0.0.0.0    C:\cygwin64\bin\less.exe

这部分是对“if_ok_button”的回复,但无法放入子评论中,但我使用以下(稍微复杂的)函数,如果我运行“def”对象类型,该函数现在已成为我的工具包中的固定装置,就像一个变量,它会返回有关该事物的所有信息的摘要,而无需我找到正确的命令 - 我一直在构建它,现在它涵盖了很多(但如果有人有任何改进,我会感谢)。

例如 def dir、def more、def abc、def get-command、def gc、def

# Find definitions for any Cmdlet, Function, Alias, External Script, Application
function def {   
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [ArgumentCompleter({ [Management.Automation.CompletionResult]::Command })]
        [string]$cmd,
        [switch]$Examples
    )

    function Write-Wrap {
        [CmdletBinding()]Param( [parameter(Mandatory=1, ValueFromPipeline=1, ValueFromPipelineByPropertyName=1)] [Object[]]$chunk )
        $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
    }

    $deferr = 0; $type = ""
    try { $type = ((gcm $cmd -EA silent).CommandType); if ($null -eq $type) { $deferr = 1 } } catch { $deferr = 1 }

    if ($deferr -eq 1) {
        if ($cmd -eq $null) { Write-Host "Object is `$null" ; return } 
        Write-Host "`$object | Convert-Json:" -F Cyan
        $cmd | ConvertTo-Json
        ""
        Write-Host "(`$object).GetType()" -F Cyan -NoNewline ; Write-Host " :: [BaseType|Name|IsPublic|IsSerial|Module]"
        ($cmd).GetType() | % { "$($_.BaseType), $($_.Name), $($_.IsPublic), $($_.IsSerializable), $($_.Module)" }
        ""
        Write-Host "`$object | Get-Member -Force" -F Cyan
        $m = "" ; $cm = "" ; $sm = ""; $p = "" ; $ap = "" ; $cp = "" ; $np = "" ; $pp = "" ; $sp = "" ; $ms = ""
        $msum = 0 ; $cmsum = 0 ; $smsum = 0 ; $psum = 0 ; $cpsum = 0 ; $apsum = 0 ; $spsum = 0 ; $ppsum = 0 ; $npsum = 0 ; $spsum = 0 ; $mssum = 0
        $($cmd | Get-Member -Force) | % {
            if ($_.MemberType -eq "Method") { if(!($m -like "*$($_.Name),*")) { $m += "$($_.Name), " ; $msum++ } }
            if ($_.MemberType -eq "CodeMethod") { if(!($cm -like "*$($_.Name),*")) { $cm += "$($_.Name), " ; $cmsum++ } }
            if ($_.MemberType -eq "ScriptMethod") { if(!($sm -like "*$($_.Name),*")) { $sm += "$($_.Name), " ; $smsum++ } }
            if ($_.MemberType -eq "Property") { if(!($p -like "*$($_.Name),*")) { $p += "$($_.Name), " ; $psum++ } }
            if ($_.MemberType -eq "AliasProperty") { if(!($ap -like "*$($_.Name),*")) { $ap += "$($_.Name), " ; $apsum++ } }
            if ($_.MemberType -eq "CodeProperty") { if(!($cp -like "*$($_.Name),*")) { $cp += "$($_.Name), " ; $cpsum++ } }
            if ($_.MemberType -eq "NoteProperty") { if(!($np -like "*$($_.Name),*")) { $np += "$($_.Name), " ; $npsum++ } }
            if ($_.MemberType -eq "ParameterizedProperty") { if(!($pp -like "*$($_.Name),*")) { $pp += "$($_.Name), " ; $ppsum++} }
            if ($_.MemberType -eq "ScriptProperty") { if(!($sp -like "*$($_.Name),*")) { $sp += "$($_.Name), " ; $npsum++ } }
            if ($_.MemberType -eq "MemberSet") { if(!($ms -like "*$($_.Name),*")) { $ms += "$($_.Name), " ; $mssum++ } }
            # AliasProperty, CodeMethod, CodeProperty, Method, NoteProperty, ParameterizedProperty, Property, ScriptMethod, ScriptProperty
            # All, Methods, MemberSet, Properties, PropertySet
        }
        if($msum -ne 0) { Write-Wrap ":: Method [$msum] => $($m.TrimEnd(", "))" }
        if($msum -ne 0) { Write-Wrap ":: CodeMethod [$cmsum] => $($cm.TrimEnd(", "))" }
        if($msum -ne 0) { Write-Wrap ":: ScriptMethod [$smsum] => $($sm.TrimEnd(", "))" }
        if($psum -ne 0) { Write-Wrap ":: Property [$psum] => $($p.TrimEnd(", "))" }
        if($npsum -ne 0) { Write-Wrap ":: AliasProperty [$apsum] => $($ap.TrimEnd(", "))" }
        if($npsum -ne 0) { Write-Wrap ":: CodeProperty [$cpsum] => $($cp.TrimEnd(", "))" }
        if($npsum -ne 0) { Write-Wrap ":: NoteProperty [$npsum] => $($np.TrimEnd(", "))" }
        if($ppsum -ne 0) { Write-Wrap ":: ParameterizedProperty [$ppsum] => $($pp.TrimEnd(", "))" }
        if($spsum -ne 0) { Write-Wrap ":: ScriptProperty [$spsum] => $($sp.TrimEnd(", "))" }
        if($mssum -ne 0) { Write-Wrap ":: ScriptProperty [$mssum] => $($ms.TrimEnd(", "))" }
        ""
        Write-Host "`$object | Measure-Object" -F Cyan
        $cmd | Measure-Object | % { "Count [$($_.Count)], Average [$($_.Average)], Sum [$($_.Sum)], Maximum [$($_.Maximum)], Minimum [$($_.Minimum)], Property [$($_.Property)]" }
    }

    if ($deferr -eq 0) {

        if ($cmd -like '*`**') { Get-Command $cmd ; break }   # If $cmd contains a *, then just check for commands, don't find definitions
   
        if ($type -eq 'Cmdlet') {
            Write-Host "`n'$cmd' is a Cmdlet:`n" -F Green
            Write-Host "SYNOPSIS, DESCRIPTION, SYNTAX for '$cmd'.   " -F Green
            Write-Host "------------"
            Write-Host ""
            Write-Host "(Get-Help $cmd).Synopsis" -F Cyan 
            Write-Host "$((Get-Help $cmd).Synopsis)"
            Write-Host ""
            Write-Host "(Get-Help $cmd).Description.Text" -F Cyan
            try {
                $arrdescription = (Get-Help $cmd).Description.Text.split("`n")
                foreach ($i in $arrdescription) { Write-Wrap $i }
            } catch { "Could not resolve description for $cmd" }
            Write-Host ""
            Write-Host "(Get-Command $cmd -Syntax)" -F Cyan
            $arrsyntax = (Get-Command $cmd -syntax).TrimStart("").Split("`n")  # Trim empty first line then split by line breaks
            foreach ($i in $arrsyntax) { Write-Wrap $i }   # Wrap lines properly to console width
            Get-Alias -definition $cmd -EA silent          # Show all defined aliases
            Write-Host "`nThis Cmdlet is in the '$((Get-Command -type cmdlet $cmd).Source)' Module." -F Green
            Write-Host ""
            Write-Host ""
        }
        elseif ($type -eq 'Alias') {
            Write-Host "`n'$cmd' is an Alias.  " -F Green -NoNewLine ; Write-Host "This Alias is in the '$((get-command -type alias $cmd).ModuleName).' Module"
            Write-Host ""
            Write-Host "Get-Alias '$cmd'   *or*    cat alias:\$cmd" -F Cyan
            cat alias:\$cmd   # Write-Host "$(cat alias:\$cmd)"   # "$((Get-Alias $cmd -EA silent).definition)"
            if ($cmd -eq '?') { $cmd = '`?' }   # To deal correctly with the wildcard '?'
            "`n'$((Get-Alias $cmd).Name)' is an alias of '$((Get-Alias $cmd).ReferencedCommand)'"
            $fulldef = (Get-Alias $cmd -EA silent).definition   # Rerun def but using the full cmdlet or function name.
            def $fulldef
            if ($Examples -eq $true) { $null = Read-Host 'Press any key to view command examples' ; get-help $fulldef -examples }
        }
        elseif ($type -eq 'Function') {
            Write-Host "`n'$cmd' is a Function.  " -F Green -NoNewline
            Write-Host "`ncat function:\$cmd   (show contents of function)`n" -F Cyan ; cat function:\$cmd ; Write-Host ""
            Write-Host "cat function:\$cmd`n" -F Cyan
            Write-Host ""
            Write-Host "SYNOPSIS, SYNTAX for '$cmd'.   " -F Green
            Write-Host "------------"
            $arrsynopsis = ((Get-Help $cmd).Synopsis).TrimStart("").Split("`n")  # Trim empty first line then split by line breaks
            $arrsyntax = (Get-Command $cmd -syntax).TrimStart("").Split("`n")    # Often synopsis=syntax for function so use Compare-Object
            if ($null -eq $(Compare-Object $arrsynopsis $arrsyntax -SyncWindow 0)) { 
                Write-Host "'(Get-Help $cmd).Synopsis'" -F Cyan -N
                Write-Host " and " -N
                Write-Host "'Get-Command $cmd -Syntax'" -F Cyan -N
                Write-Host " have the same output for this function:`n"
                foreach ($i in $arrsynopsis) { Write-Wrap $i }   # Wrap lines properly to console width
            } else { 
                Write-Host "(Get-Help $cmd).Synopsis" -F Cyan
                foreach ($i in $arrsynopsis) { Write-Wrap $i }   # Wrap lines properly to console width
                Write-Host ""
                Write-Host "Get-Command $cmd -Syntax" -F Cyan
                foreach ($i in $arrsyntax) { Write-Wrap $i }     # Wrap lines properly to console width
            }
            Write-Host "The '$cmd' Function is in the '$((get-command -type function $cmd).Source)' Module." -F Green
            Write-Host ""
            if ($Examples -eq $true) { $null = Read-Host "Press any key to view command examples" ; get-help $cmd -examples }
            Write-Host ""
        }
        elseif ($type -eq 'ExternalScript') {   # For .ps1 scripts on path
            $x = gcm $cmd
            Write-Host "`n'$cmd' is an ExternalScript (i.e. a .ps1 file on the path)." -F Green
            Write-Host "`n$($x.Path)`n" -F Green
            Write-Host "`n$($x.ScriptContents)"
            Write-Host ""
            if ($Examples -eq $true) { $null = Read-Host "Press any key to view command examples" ; get-help $cmd -Examples }
            elseif ($Synopsis -eq $true) { $null = Read-Host "Press any key to view command examples" ; (get-help $cmd).Synopsis }
            elseif ($Syntax -eq $true) { $null = Read-Host "Press any key to view command examples" ; Get-Command $cmd -Syntax }
            Write-Host ""
        }
        elseif ($type -eq 'Application') {      # For .exe etc on path
            Write-Host "`n'$cmd' was found. It is an Application (i.e. a .exe or similar located on the path)." -F Green
            Write-Host "`n$(where.exe $cmd)" -F Green
            Write-Host ""
            Read-Host "Press any key to open cmd.exe and try '$cmd /?'" ; cmd.exe /c $cmd /? | more
            Write-Host ""
        }
    } elseif ((get-module -ListAvailable -Name $cmd) -ne $null) {
        # https://stackoverflow.com/questions/28740320/how-do-i-check-if-a-powershell-module-is-installed
        ""
        (get-module $cmd).path
        (get-module $cmd).ExportedFunctions
        "ExportedCommands (also note: get-command -Module $cmd)"
        (get-module custom-tools).ExportedCommands
        ""
        echo "get-module $cmd | get-member  # Just show the members"
        echo "get-module $cmd | fl *        # Show the contents of every member"
    }
    else {
        if ($cmd.length -eq 0) { "`n'$cmd': No command definition found. The command may require to be surround by ' or `"`nif it contains special characters (such as 'def `"&`"').`n" }
        else { "`nInput is not a command, so no command definition search.`n" }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM