Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simulating `ls` in Powershell

Tags:

powershell

I'm trying to get something that looks like UNIX ls output in PowerShell. This is getting there:

Get-ChildItem | Format-Wide -AutoSize -Property Name

but it's still outputting the items in row-major instead of column-major order:

PS C:\Users\Mark Reed> Get-ChildItem | Format-Wide -AutoSize -Property Name

Contacts      Desktop       Documents     Downloads    Favorites    
Links         Music         Pictures      Saved Games
Searches      Videos

Desired output:

PS C:\Users\Mark Reed> My-List-Files 

Contacts        Downloads       Music           Searches
Desktop         Favorites       Pictures        Videos
Documents       Links           Saved Games 

The difference is in the sorting: 1 2 3 4 5/6 7 8 9 reading across the lines, vs 1/2/3 4/5/6 7/8/9 reading down the columns.

I already have a script that will take an array and print it out in column-major order using Write-Host, though I found a lot of PowerShellish idiomatic improvements to it by reading Keith's and Roman's takes. But my impression from reading around is that's the wrong way to go about this. Instead of calling Write-Host, a script should output objects, and let the formatters and outputters take care of getting the right stuff written to the user's console.

When a script uses Write-Host, its output is not capturable; if I assign the result to a variable, I get a null variable and the output is written to the screen anyway. It's like a command in the middle of a UNIX pipeline writing directly to /dev/tty instead of standard output or even standard error.

Admittedly, I may not be able to do much with the array of Microsoft.PowerShell.Commands.Internal.Format.* objects I get back from e.g. Format-Wide, but at least it contains the output, which doesn't show up on my screen in rogue fashion, and which I can recreate at any time by passing the array to another formatter or outputter.

like image 625
Mark Reed Avatar asked Jun 27 '15 00:06

Mark Reed


1 Answers

This is a simple-ish function that formats column major. You can do this all in PowerShell Script:

function Format-WideColMajor {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline)]
        [AllowNull()]
        [AllowEmptyString()]
        [PSObject]
        $InputObject,

        [Parameter()]
        $Property
    )

    begin {
        $list = new-object System.Collections.Generic.List[PSObject]
    }

    process {
        $list.Add($InputObject)
    }

    end {
        if ($Property) {
            $output = $list | Foreach {"$($_.$Property)"}
        }
        else {
            $output = $list | Foreach {"$_"}
        }

        $conWidth = $Host.UI.RawUI.BufferSize.Width - 1
        $maxLen = ($output | Measure-Object -Property Length -Maximum).Maximum

        $colWidth = $maxLen + 1

        $numCols = [Math]::Floor($conWidth / $colWidth)
        $numRows = [Math]::Ceiling($output.Count / $numCols)

        for ($i=0; $i -lt $numRows; $i++) {
            $line = ""
            for ($j = 0; $j -lt $numCols; $j++) {
                $item = $output[$i + ($j * $numRows)]
                $line += "$item$(' ' * ($colWidth - $item.Length))"
            }
            $line
        }
    }
}
like image 155
Keith Hill Avatar answered Oct 10 '22 20:10

Keith Hill