Run a function on each element of a list in powershell

Tag: powershell Author: lingyun1696 Date: 2009-07-20

I have a directory full of file pairs. Each pair of files have the same name with the extensions of mp3 and cdg (karaoke files!). I would like to use powershell to get the list of all distinct file names with no extensions

I've gotten as far as:

dir -recurse -filter "*.mp3" | select-object Name | sort

But I can't quite figure out how to pass each Name to [System.IO.Path]::GetFileNameWithoutExtension

how would I do this?

Best Answer

What you're looking for is the for-each (%) filter (not precisely sure if it's a filter or a cmdlet but it has the same usage syntax).

Try the following

dir -recurse -filter "*.mp3" | 
  %{ $_.Name } |
  %{ [IO::Path]::GetFileNameWithoutExtension($_) } |
  sort

EDIT Update

I changed my answer from "select-object Name" to "%{ $_.Name}". The former essentially takes the Name property off of the pipeline value and creates a new object with a single property of the specified name with the value on the original object. The latter will process every value in the pipeline and pass the result of executing $_.Name down the pipeline.

comments:

That works but a) it gives me something like: @{Name=Mr Bungle - Backstrokin' - How do I get rid of the @{Name= part? and b) what the heck did I just do?
@George, I updated my answer to get rid of the @Name part. I'll add a response as to why that happens
Awesome, thanks
foreach-object is a function. You can verify this with gcm or simply by observing that % { "begin" } { "processing $_" } { "end" } works as expected.
ForEach-Object is a cmdlet here.

Other Answer1

dir -recurse -filter ".mp3"| select @{name='Name';Expression={[System.IO.Path]::GetFileNameWithoutExtension($.Name)}} | sort

comments:

+1. Many people forget select's "hashtable syntax." Too bad it's so ugly. Would be much nicer to write select @{ Name = {some-expression}, Path = {some-otherexpression} }
Agreed Richard.

Other Answer2

If you hate typing %{$_.foo} all the time like I do, try Get-PropertyValue (alias: gpv) from PSCX.

More musings here for the suitably geeky: http://richardberg.net/blog/?p=55

Other Answer3

Now that PowerShell v2 is RTMd, you can select the BaseName member:

dir -recurse -filter *.mp3 | select BaseName | sort