Shell – How to sort objects by third column in Powershell

powershellpowershell-2.0sorting

I've a text file like this:

4108689096 2531 ./ssss/132432.odt
481446057 2293 ./abc/a.txt
3157353085 1096 ./dsjvbjf/c.docx
653380669 1824 ./bcd/x.avi

And I'd like to achieve in Powershell to sort the list by the third column, but Sort-Object seems to sort this list by the file name (by the first character after the last / in every row) whatever I do.

I'd like to achieve something like this:

481446057 2293 ./abc/a.txt
653380669 1824 ./bcd/x.avi
3157353085 1096 ./dsjvbjf/c.docx
4108689096 2531 ./ssss/132432.odt

So I'd like to sort by the third column as a string including ., / characters.


Edit #1: Some relevant code

# Gets a relative path based on a base and a full path (to file)
# 
# Usage: RelativePath <path to file> <base path>
# 
# Note: Specifying arguments is mandatory.
function global:RelativePath
{
    param
    (
        [string]$path = $(throw "Missing: path"),
        [string]$basepath = $(throw "Missing: base path")
    )

    return [system.io.path]::GetFullPath($path).SubString([system.io.path]::GetFullPath($basepath).Length + 1)
}

# Calculates CRC checksums for all files in the specified directory and writes
# the checksums to a file
# 
# Usage: CRCSumAll <path to folder to check> <file conatining checksums>
# 
# Note: Specifying arguments is mandatory.
function global:CRCSumAll
{
    param($inputpath,$outputfile)

    $allfiles=get-childitem $inputpath -rec | Where-Object {!($_.psiscontainer)} | Sort-Object Name

    new-item -force -type file $outputfile

    cd $inputpath
    foreach ($file in $allfiles)
    {
        $relfile=RelativePath $file.fullname $inputpath
        $relfile=$relfile -replace("\\","/")
        $relfile="./$relfile"
        cksum.exe $relfile | Out-File -Encoding OEM -Append $outputfile
    }
}

Edit #2: Solution

I realized what was the problem. I added the relative paths after sorting. So the correct code is:

function global:CRCSumAll
{
    param($inputpath,$outputfile)

    $allfiles=get-childitem $inputpath -rec | Where-Object {!($_.psiscontainer)} #| Sort-Object Name

    new-item -force -type file $outputfile

    cd $inputpath
    foreach ($file in $allfiles)
    {
        $relfile=RelativePath $file.fullname $inputpath
        $relfile=$relfile -replace("\\","/")
        $relfile="./$relfile"
        $relfile | Out-File -Encoding OEM -Append $outputfile
    }

    $sorted=Get-Content $outputfile | Sort-Object
    new-item -force -type file $outputfile
    $sorted | Out-File -Encoding OEM -Append $outputfile

    $forcksum=Get-Content $outputfile
    new-item -force -type file $outputfile
    $forcksum | Foreach-Object { cksum.exe $_ | Out-File -Encoding OEM -Append $outputfile}
}

Now I only have to clean up the code a little bit, because writing a file three times is really ugly. 🙂

Best Answer

Try something like this:

Import-CSV C:\Path\To\File.txt -Header ('foo', 'bar', 'wombat') -delimiter ' ' | Sort-Object wombat

I'll leave my original answer since it meets the criteria as long as the input has well defined columns. Based on the comments, the solution is to sort the array at creation:

$allfiles=get-childitem $inputpath -rec | Where-Object {!($_.psiscontainer)} | Sort-Object Name
cd $inputpath
foreach ($file in $allfiles) {cksum.exe $file | Out-File -Append $pathtooutputfile}
Related Question