如何在表格中按列排列并按字典顺序编写列表?

6

我有Get-ChildItem的结果,我想遍历它们,并显示它们的名称。如果我仅使用Write-Host,则默认情况下会按行列出如下:

PerfLogs  Program Files  Program Files (x86)  Python31  Temp  Users  Windows

然而,假设我知道我想将它分成x列,我希望输出的格式如下:
PerfLogs                  Python31     Windows
Program Files             Temp
Program Files (x86)       Users

如您所见,它首先按列列出,然后再横向排列。

有什么办法可以得到这样的输出吗?理想情况下,它应该使用尽可能多的列来适应屏幕,并在每个列中将名称靠左对齐。

更新:感谢Roman,我现在可以使用带有目录颜色的Linux风格“ls”输出。基于他更新后的脚本,我有:

function color-ls
{
    dir $args | Format-High -Print {    
        $item = $args
        $fore = $host.UI.RawUI.ForegroundColor        
        $host.UI.RawUI.ForegroundColor = .{     
            if ($item[1].psIsContainer) {'Blue'}
            elseif ($item[1].Extension -match '\.(exe|bat|cmd|ps1|psm1|vbs|rb|reg|dll|o|lib)') {'Red'}
            elseif ($item[1].Extension -match '\.(zip|tar|gz|rar)') {'Yellow'}
            elseif ($item[1].Extension -match '\.(py|pl|cs|rb|h|cpp)') {'Cyan'}
            elseif ($item[1].Extension -match '\.(txt|cfg|conf|ini|csv|log|xml)') {'Green'}
            else {$fore}
        }
        write-host $args[0] -NoNewLine
        $host.UI.RawUI.ForegroundColor = $fore
    }
}

Output:

http://dl.dropbox.com/u/2809/lscolor.png


我很高兴你按照设计的方式完美地重用了更新后的脚本。感谢你的启发式想法。如果PowerShell内置此功能将会很不错,我已经提交了建议: https://connect.microsoft.com/PowerShell/feedback/details/620452/format-wide-add-an-option-to-output-by-columns - Roman Kuzmin
我应该把 Format-High.ps1 文件放在哪里?我已经尝试将其放在 C:\Users\X\Documents\WindowsPowerShell\Scripts\Format-High.ps1 目录下,也尝试将其与包含 color-ls 的配置文件 C:\Users\X\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 放在同一目录下,但是我仍然收到错误信息 The term 'Format-High.ps1' is not recognized - abulka
1个回答

7

这是一个有趣的想法和任务。

更新:更新后的脚本包含了一些修复和改进。它还允许以多种方式自定义输出。请在脚本注释中查看示例。

脚本格式-High.ps1:

<#
.SYNOPSIS
    Formats input by columns using maximum suitable column number.

.DESCRIPTION
    Format-High prints the specified property, expression, or string
    representation of input objects filling the table by columns.

    It is named in contrast to Format-Wide which prints by rows.

.EXAMPLE
    # just items
    ls c:\windows | Format-High

    # ditto in colors based on PSIsContainer
    ls c:\windows | Format-High -Print {$c = if ($args[1].PSIsContainer) {'yellow'} else {'white'}; Write-Host $args[0] -ForegroundColor $c -NoNewline}

    # just processes, not good
    ps | Format-High

    # process names, much better
    ps | Format-High Name

    # custom expression and width
    ps | Format-High {$_.Name + ':' + $_.WS} 70

    # process names in colors based on working sets
    ps | Format-High Name 70 {$c = if ($args[1].WS -gt 10mb) {'red'} else {'green'}; Write-Host $args[0] -ForegroundColor $c -NoNewline}
#>

param
(
    [object]$Property,
    [int]$Width = $Host.UI.RawUI.WindowSize.Width - 1,
    [scriptblock]$Print = { Write-Host $args[0] -NoNewline },
    [object[]]$InputObject
)

# process the input, get strings to format
if ($InputObject -eq $null) { $InputObject = @($input) }
if ($Property -is [string]) { $strings = $InputObject | Select-Object -ExpandProperty $Property }
elseif ($Property -is [scriptblock]) { $strings = $InputObject | ForEach-Object $Property }
else { $strings = $InputObject }
$strings = @(foreach($_ in $strings) { "$_" })

# pass 1: find the maximum column number
$nbest = 1
$bestwidths = @($Width)
for($ncolumn = 2; ; ++$ncolumn) {
    $nrow = [Math]::Ceiling($strings.Count / $ncolumn)
    $widths = @(
        for($s = 0; $s -lt $strings.Count; $s += $nrow) {
            $e = [Math]::Min($strings.Count, $s + $nrow)
            ($strings[$s .. ($e - 1)] | Measure-Object -Maximum Length).Maximum + 1
        }
    )
    if (($widths | Measure-Object -Sum).Sum -gt $Width) {
        break
    }
    $bestwidths = $widths
    $nbest = $ncolumn
    if ($nrow -le 1) {
        break
    }
}

# pass 2: print strings
$nrow = [Math]::Ceiling($strings.Count / $nbest)
for($r = 0; $r -lt $nrow; ++$r) {
    for($c = 0; $c -lt $nbest; ++$c) {
        $i = $c * $nrow + $r
        if ($i -lt $strings.Count) {
            & $Print ($strings[$i].PadRight($bestwidths[$c])) $InputObject[$i]
        }
    }
    & $Print "`r`n"
}

同意排序,这太好了。我正在学习PowerShell,你能告诉我$widths = .{}中的.{}是什么吗? - esac
在宽度求和之后,应该是 $bestwidths = ($widths)。如果只有一个文件,则会抛出异常。 - esac
.{}运算符(在当前作用域中调用)+被它调用的脚本块。但在这种情况下,有一个更好的构造@(),它还修复了您注意到的错误。我很快会更新代码(还有其他小缺陷)。 - Roman Kuzmin
嗨Roman,你知道为什么在目录中没有任何文件时会挂起吗? - esac
一个错误。我已经更新了代码:用if ($nrow -le 1)替换了if ($nrow -eq 1) - Roman Kuzmin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接