32

How does one rename the following files (New => Old):

filename__Accelerated_C____Practical_Programming_by_Example.chm -> C Practical Programming by Example.chm

filename__Python_Essential_Reference__2nd_Edition_.pdf -> Python Essential Reference 2nd Edition.pdf

filename__Text_Processing_in_Python.chm -> Text Processing in Python.chm

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
Dean
  • 1,103
  • 4
  • 17
  • 29

3 Answers3

49

Try this one:

Get-ChildItem directory `
        | Rename-Item -NewName { $_.Name -replace '^filename_+','' -replace '_+',' ' }

Note that I just pipe the objects to Rename-Item, it is not really needed to do it via Foreach-Object (alias is %).

Update

I haven't anything documented about the 'magic' with scriptblocks. If I remember correctly, it can be used if the property is ValueFromPipelineByPropertyName=$true:

function x{
    param(
        [Parameter(ValueFromPipeline=$true)]$o,
        [Parameter(ValueFromPipelineByPropertyName=$true)][string]$prefix)
    process {
        write-host $prefix $o
    }
}
gci d:\ | select -fir 10 | x -prefix { $_.LastWriteTime }
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
stej
  • 28,745
  • 11
  • 71
  • 104
  • 1
    Woohoo. +1 for eliminating the unnecessary `Foreach` pipeline stage. :-) – Keith Hill Apr 07 '11 at 14:40
  • hey cool. The docs don't say you could use a scriptblock as a param there. Is this a feature of many other cmdlets? – zdan Apr 07 '11 at 17:19
  • @zdan, I don't know where it is documented. Maybe found it on a blog. Nobody has answered so far (question on Twitter). See my edited answer. – stej Apr 08 '11 at 08:14
34

This should work:

ls | %{ ren $_ $(($_.name -replace '^filename_+','') -replace '_+',' ') }

Expanding the aliases and naming all argument, for a more verbose but arguably more understandable version, the following is equivalent

Get-ChildItem -Path . | ForEach-Object { Rename-Item -Path $_ -NewName $(($_.Name -replace '^filename_+','') -replace '_+',' ') }
LudvigH
  • 3,662
  • 5
  • 31
  • 49
zdan
  • 28,667
  • 7
  • 60
  • 71
  • 2
    Why using `$` in the second parameter. I found this working too: `ls | % { ren $_ (($_ -replace 'filename_+','') -replace '_+',' ')}` – Emiliano Poggi Apr 07 '11 at 06:42
  • 1
    forgot my comment, $ is necessary to cut off last space before the file extension :). Your regex works perfectly! – Emiliano Poggi Apr 07 '11 at 06:49
  • In case anybody else has the same problem: If, for whatever reason, using the foreach-block results in a "cannot rename because item does not exist" error, try using the script-block as argument to -NewName, as shown in the answer by user @stej (works for me). I cannot understand why this should make any difference. Maybe someone has an idea? – gimpf Feb 26 '16 at 14:38
  • This answer could be considerably improved if it pointed to some documentation to help beginner readers understand the regex machinery in it. – Owen Feb 20 '22 at 22:04
1

Try this out:

$filename = $filename -creplace '_+\.', '.'
$filename = $filename -creplace '_+', ' '
ridgerunner
  • 33,777
  • 5
  • 57
  • 69