7

I've been challenged by a friend to do the following:

"Find the quickest and easiest way of sorting a directory listing by the LAST character of the filenames."

He's done it on Linux using the following:

ls | rev | sort | rev 

I'd like to show him the powershell alternative, but I'm only just starting to learn powershell and I can't do it. So, I'm cheating and asking for your help.

3
  • 1
    Actually that is sorting it by not just the last character but by all the characters following. Sam Cogan's answer below is strictly by the last character and ignores any following characters.
    – Sim
    Dec 4, 2009 at 10:35
  • Before anyone votes to migrate this question again, have a look at this: meta.stackexchange.com/questions/32471/…
    – raven
    Dec 10, 2009 at 16:20
  • I think this challenge it is misleading and furthermore not a fair comparison of linux to PowerShell. If rev were to only sort the last character then it would be fair. Also what might be more fair would be to also ask people to write bash or whatever to only sort the last character, and not simply do: "ls | rev | sort | ls". But honestly, why anyone would want this odd function I'm still scratching my head over, except perhaps to try and convince someone that PowerShell can be as compact as sh, but with a comparison of apples to oranges? Jan 18, 2014 at 15:47

6 Answers 6

3

Unfortunately Powershell does not have a nice easy reverse method, so instead you have to get the last letter of the string and sort by that. This is one way i've done it:

dir| sort {$_.name.Substring($_.name.length-1)}

As has been pointed out, this will sort strictly by the last letter only, whereas I the Linux version will sort by the last and then subsequent letters, so there may be a better way of doing this, or you may have to introduce some looping if you want it that way.

3
  • That's brill. Not as short as the Linux alternative, but still pretty good.
    – Richard
    Dec 4, 2009 at 10:29
  • I noticed too that this only sorts by the last letter, unlike the linux version. However the challenge stated "by the LAST character" so this answer answers the question, even if the two solutions aren't equal.
    – Richard
    Dec 4, 2009 at 10:48
  • Due to some confusion this question was migrated to Stack Overflow and then unmigrated. Keith Hill on Stack overflow added the shorter answer ls|sort{"$_"[-1]}
    – Richard
    Dec 9, 2009 at 21:01
9

You can try this:

dir| sort {$_.name[-1]}
0
2
dir | sort -Property @{Expression ={$n = $_.Name.ToCharArray(); [Array]::Reverse($n);[String]::Join("",$n)}}

Not as short as the unix version, mostly because there isn't a String.Reverse() function in the .NET Framework. Basically this works by telling sort 'sort by computing this expression on the input arguments'.


Now, if any unix shell does better than

dir | sort -Property Length -Descending

to print all the files with the largest one first, I'd be interested to see it.

2
  • 4
    How about 'ls -S'?
    – Bryan
    Dec 5, 2009 at 17:21
  • Wow! Didn't know about this one :D Nice one :)
    – AntonioCS
    Dec 5, 2009 at 21:31
2

I'm sure someone can do this better, but here is one way that is fully compatible with lynix. It has the benefit of leaving you with a reusable rev string function for your toolbox, i.e. it sorts the entire string and not just the last character:

function rev ($s) {return -join ($s[$s.Length..0])}

dir | foreach{rev($_.name)} | sort | foreach{rev($_)}

I think the foreach's here nicely demonstrate how PowerShell pipes are arrays and not simply strings like in *nix.

It took me a little while to realize that I had to use only $_ and not $_.name inside the 2nd foreach. So I've learned something about variations in the array content from one pipe to the next.

*Credit for the guts of my rev function goes to http://rosettacode.org/wiki/Reverse_a_string#PowerShell


Works like lynix:

  • dir | sort -Property @{Expression ={$n = $_.Name.ToCharArray(); [Array]::Reverse($n);[String]::Join("",$n)}}

Sort of works like lynix, but very, very slow:

  • ls -n|sort{$_[3e3..0]}

Do not work like lynix, i.e. fail to sort all characters of the file names; (only sorts the very last character of the string):

  • dir| sort {$.name.Substring($.name.length-1)}
  • dir| sort {$_.name[-1]}
  • ls|sort{$_.Name[-1]}
  • ls|sort{"$_"[-1]}
  • ls -n|sort{$_[-1]}
1
  • This could be improved by making the rev function accept an array. Then you could eliminate the forEach in the code, as the function would call it. You could add a couple things to make the ls | rev | sort | rev completely valid on its own. :-) Jun 29, 2017 at 15:48
1

Shay's variant is way shorter than the accepted answer by indexing into the string but even that can be improved. You can shorten it even more by excluding unnecessary spaces and using a shorter alias:

ls|sort{$_.Name[-1]}

Also you can use the (abbreviated) -Name argument to Get-ChildItem:

ls -n|sort{$_[-1]}

which will return strings directly.

If you really want to sort by the reverse string, then the following works (but is slow):

ls -n|sort{$_[3e3..0]}

You can make it faster if you have an upper bound on the file name's length.

2
  • Quoting from the question: »Find the quickest and easiest way of sorting a directory listing by the LAST character of the filenames.«. It just needs to sort by the last character. If the easiest way of doing so is reversing the string, so be it, but if the easiest way of doing so is by just sorting by the last character, then this solves the task as well. The question wasn't about »How can I do this snippet of Unix shell exactly the same in PowerShell?«.
    – Joey
    Jan 18, 2014 at 15:31
  • Sorry. I got it wrong. Jan 18, 2014 at 16:24
-1
ls|sort{"$_"[-1]}
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .