首页 > 解决方案 > PowerShell 'less' tool

问题描述

This is not a duplicate of the various other questions around this (I reviewed them and this was not answered in the ones that I saw). Those other questions revolve around Out-Host -Paging and more (even if they mention less in the question title).

To focus on this specific point, does anyone know of a PowerShell method of replicating the functionality of less, but on Microsoft Windows environments? i.e. giving us the ability to scroll down and up through a document (line by line with cursor keys or page by page with the PgUp / PgDn keys) to view help and other files (e.g. so that we can do Get-Help Get-ChildItem -Full | less).

This would be very useful. I am not after a 3rd party executable less tool (because that won't be pipeline enabled etc) for Windows (there are many of course). I believe that there is something in PSCX like this, but whenever I try to install that, I see lots of conflicts and I'm not sure to use -AllowClobber in case it breaks something else. Maybe on that though, if there is a less in there, has anyone been able to split out that function and use independently of PSCX?

标签: powershellconsole

解决方案


Get-Help Get-ChildItem -Full | less works just fine on Unix-like platforms, using the given platform's less utility (typically, /usr/bin/less) - no extra work needed.

I am not after a 3rd party executable less tool (because that won't be pipeline enabled etc)

Any external program (utility) that reads from stdin (standard input) and outputs to stdout (standard output) is by definition pipeline-enabled, albeit invariably only with respect to text: data sent to such utilities is converted to text, and data returned from such utilities is interpreted as text.

On Windows, only the - feature-limited - more.com pager is available by default - see below.

However, it is possible to install less on Windows:

  • If you have a Linux distro for the WSL installed, you can simply pipe to wsl less; e.g.:

    • Get-Help Get-ChildItem | wsl less
    • Caveat: PageUp / PageDown seemingly do not work when invoked from PowerShell, but f (forward) and b (back) provide the same utility.
  • Otherwise, consider installing the less.exe Windows console application (pick the version inside the most recent folder) that is part of the GnuWin project (the installer requires admin privileges).

    • This gives you normal PageUp / PageDown support.

Note: There's another port of less to Windows, which comes bundled with other utilities; haven't personally tried it: UnxUtils.

Caveats:

  • less apparently expects UTF-8 input, irrespective of the active OEM code page, and additionally only displays non-ASCII characters correctly if [console]::OutputEncoding] is set to UTF-8.

    • Therefore, both $OutputEncoding and [console]::OutputEncoding] must be set to UTF-8 ([Text.Utf8Encoding]::new()) for the display of non-ASCII characters to work properly. (In PowerShell [Core] v6+, $OutputEncoding defaults to UTF-8, but [console]::OutputEncoding] still reflects the system's OEM code page.)

    • See the bottom section for how to make the command more / the help function in PowerShell use less instead of more.com, via a custom more function that also ensures use of UTF-8 encoding.

  • GnuWin less.exe version 394 (current as of this writing, but published in 2006-01-03) sometimes acts erratically and displays nothing; starting a new session makes the problem go away.


The - less powerful (no pun intended) - Windows counterpart to less is more (more.com), which accepts text via stdin / the pipeline or via a filename arguments.

Remarkably, more.com only seems to support paging down, with space, and not back up; that is, you can't scroll back - see here.

PowerShell's own Out-Host -Paging has the same limitation.

  • Windows PowerShell provides a built-in wrapper function around more.com also named more (which means that executing just more executes the function), which ensures that the content of specified files is output with the encoding of the active OEM code page, which is what more.com expects.

  • PowerShell [Core] 6+ doesn't provide this wrapper anymore.

In both editions, the built-in help function, which itself wraps Get-Help, implicitly pipes the latter's output to more - invariably in Windows PowerShell, by default in PowerShell 6+ on Windows (on Unix, it defaults to less.

In PowerShell 6+, you can also define a custom pager by setting the $env:PAGER variable to the command line you want invoked for paging help output.

In Windows PowerShell, your only option is to replace / define a custom more function (which would also work in PowerShell 6+).

In other words: Something like the following gives you interactively paged output by default:

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

If you have less available on Windows and want to use it instead of more:

Overwrite the built-in / define a more function as follows (in your $PROFILE file):

  • Use of less via WSL:
# 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' }
  • Use of 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' }

Note: This makes more only accept pipeline input, but it wouldn't be hard to extend the function to accept filename arguments too.


If the following conditions are met, there is a simpler solution, suggested by David Hatch:

  • You have GnuWin less.exe installed.

  • You don't need support for non-ASCII characters.

  • You do, but your sessions are already configured to set both $OutputEncoding and [console]::OutputEncoding to UTF-8. ($OutputEncoding defaults to UTF-8 in PowerShell [Core] v6+, but not [console]::OutputEncoding]).

    • See this answer for how to switch your PowerShell sessions to use UTF-8 consistently, via $PROFILE.

    • See this answer for how to configure Windows 10 system-wide to use code page 65001 == UTF-8, but note that the feature is still in beta as of this writing, and that it has side effects and limitations; notably, it makes Windows PowerShell commands that use the active ANSI code page (Get-Content / Set-Content) then default to UTF-8.

Windows PowerShell:

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

PowerShell [Core] v6+:

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

推荐阅读