Sort-Object Name not returning order expected

Viewed 171

I have some powershell code that gets all the files in a directory and sorts them by name. I am confused on how the sort is working and would like some clarification.

The files are listed as :

1_doc.pdf,
2_doc.pdf,
3_doc.pdf
.....
10_doc.pdf,
11_doc.pdf

When powershell does the sort, it puts them as

1_doc.pdf,
10_doc.pdf,
11_doc.pdf
.....
19_doc.pdf,
2_doc.pdf

I can see that it is looking at the first character and then looking at the second character to do the sort but do I have to rename everything to get it to sort as expected?

2 Answers

Assuming there will always be an underscore on your file names and the files will always start with numbers you could use these 2 options:

$files = @'
1_doc.pdf
10_doc.pdf
11_doc.pdf
19_doc.pdf
2_doc.pdf
'@ -split '\r?\n'

$files | Sort-Object {[int]$_.Split('_')[0]}
$files | Sort-Object {[int][regex]::Match($_,'^\d+(?=_)').Value}

So the code should look something like this:

Get-ChildItem path/to/pdf -Filter *.pdf |
Sort-Object {[int]$_.Name.Split('_')[0]}
Get-ChildItem path/to/pdf -Filter *.pdf |
Sort-Object {[int][regex]::Match($_.Name,'^\d+(?=_)').Value}

Adding another option using -replace, thanks mklement0

$files | Sort-Object {[int]($_.Name -replace '_.*')}

To explain why does this happen when sorting files ?

This should explain why we convert the numbers from [string] to [int] when sorting:

# String
'1' -lt '2' => True
'10' -lt '2' => True

# Integer
1 -lt 2 => True
10 -lt 2 => False

I would just as soon rename them.

dir | 
rename-item -newname { [int]($_ -split '_')[0] | % tostring 00_doc\.pdf } -whatif

What if: Performing the operation "Rename File" on target 
      "Item: C:\Users\admin\foo\10_doc.pdf 
Destination: C:\Users\admin\foo\10_doc.pdf".

What if: performing the operation "Rename File" on target 
       "Item: C:\Users\admin\foo\1_doc.pdf 
Destination: C:\Users\admin\foo\01_doc.pdf".
Related