2010-11-08 3 views
5

У меня есть результат Get-ChildItem, и я хочу повторить их и показать их имена. По умолчанию, если я просто использую Write-Host тогда я получаю его в списке вдоль строки, как это:Как написать список, отсортированный лексикографически в сетке, указанной столбцом?

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

Однако, сказать, что я знаю, что я хочу разделить на х колонок, я хочу, выход, как это вместо:

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

Как вы можете видеть, он сначала перечисляет его по столбцам, а затем поперек.

Любая идея, как получить такой результат? В идеале он будет использовать большинство # столбцов, которые могут поместиться на экране с именем, выровненным слева в каждом столбце.

ОБНОВЛЕНИЕ: благодаря Роману, теперь у меня есть мой 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 
    } 
} 

Выход:

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

+0

Я рад, что вы повторно обновленный сценарий именно таким образом, он был разработан. Спасибо за вдохновляющую идею. Было бы хорошо, если PowerShell имеет этот встроенный модуль, я представил предложение: https://connect.microsoft.com/PowerShell/feedback/details/620452/format-wide-add-an-option-to-output -by-columns –

ответ

6

Это интересная идея и задача.

UPDATE: обновленный скрипт содержит несколько исправлений и улучшений. Он также позволяет настраивать вывод несколькими способами. См. Примеры в комментариях к скрипту.

Script Format-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" 
} 
+0

Согласился на сортировку, это чертовски хорошо. Я просто изучаю powershell, можете ли вы указать мне на что. {} Делает в $ widths =. {}? – esac

+0

после суммирования ширины, он должен быть $ bestwidths = ($ widths) .. если есть только один файл, он выдает исключение. – esac

+0

'. {}' - оператор * dot * (вызов в текущей области) + блок сценария, вызываемый им. Но в этом случае есть лучшая конструкция '@()', которая также исправляет ошибку, которую вы заметили. Я скоро обновлю код (есть и другие незначительные недостатки). –