0

Current state

I have a list of files which are numbered. This is an example (there are a lot more files in reality):

01 File.sql
02 File.sql
02 another_file.sql
02 a_third_file.sql
03 File.sql
04 File.sql
.....

Desired outcome

As you can see the files are numbered, but some of the files has the same number. What I want to do is to loop through them all and re-number them to make the list look something like this:

01 File.sql
02 File.sql
03 another_file.sql
04 a_third_file.sql
05 File.sql
06 File.sql
07 File.sql
.....

What I've tried

I have come up with this powershell script that allmost works:

$x = 1
Get-ChildItem "*.sql" | Rename-Item -NewName {$_.Name -replace '[0-9][0-9] ', "$x "}

What this script does is it goes through all the files and removes their current number and replaces it with what I have stored in $x. As of now the only error with my script is that all of the files get's the number 1 since I dont increment it anywhere.

So to the actual question

Where in my script can I increment $x? Or maybe I have to rewrite this as a loop somehow to be able to increment it efter each rename?

wenzzzel
  • 643
  • 2
  • 6
  • 17
  • Instead of piping directly to `Rename-Object`, perhaps you should consider piping to `ForEach-Object`. – Jeff Zeitlin May 15 '19 at 13:56
  • Tried it like this: `$x = 1 Get-ChildItem "*.sql" | ForEach-Object {$x=$x+1} | Rename-Item -NewName {$_.Name -replace '[0-9][0-9] ', "$x "} -WhatIf` but it seems as if the `Rename-Item`-part is'nt executed. Am I doing it wrong? – wenzzzel May 15 '19 at 14:06

4 Answers4

2

I would say a quick and easy way to do this would be :

$x = 0
foreach ( $item in $( Get-ChildItem "PATH" "*.txt" ) ){
    $x++
    Rename-Item $item.fullName -newname $( $item.Name -replace '[0-9][0-9] ', "$x " )
}

This however performs no error checking, so if a file name already exists then it'll error for that item.

Maybe do two sweeps if you hit any errors? Or throw in an IF ( Test-Path ...) after $x++

*Edit - Changed $x to 0 so the first rename is 1

Graham J
  • 457
  • 1
  • 6
  • 15
  • 1
    This did the job! (except for the `"PATH"` that I changed to `-Path`) Also I don't think the error checking is going to be a problem since it increments on every file name I think the odds that there already is a file with that exact name is minimal. – wenzzzel May 15 '19 at 14:12
  • 1
    I also added a `^`to the replace like this: `replace '^[0-9][0-9] '` since some of the files had numbers later in the filename as well and I only want a match where the numbers are the first thing in the filename. – wenzzzel May 15 '19 at 15:12
1

You can use foreach with replace and simple regex for that... also If you want to keep the first files with 0 before the number like 01/02/03 until 10, I added an if statement for that... hope it helps

$i = 1
foreach ($file in Get-ChildItem C:\targetPath) # Change to valid path
{
    if ($i -lt 10) {
    Rename-Item $file.FullName -NewName "0$i $($file.BaseName -replace '^\d+\s').sql"
    }

    else {
    Rename-Item $file.FullName -NewName "$i $($file.BaseName -replace '^\d+\s').sql"
    }
$i++
}
Avshalom
  • 8,657
  • 1
  • 25
  • 43
0

Note that you can use range wildcards:

 Get-ChildItem '[0-9][0-9] *.sql'

You can try scoping the variable if you really want to do it that way:

 Rename-Item -NewName {$_.Name -replace '[0-9][0-9] ', "$x "; $global:x++} -whatif

Use script instead of global in a script.

js2010
  • 23,033
  • 6
  • 64
  • 66
0

To put together several tips:

  • As Rename-Item accepts pipelined input, there is no need to iterate with a foreach.
  • put the Get-ChildItem in parentheses to execute it first and not get mangled by changing content.
  • use a wildcard/range to select the old numbers
  • anchor the replace Regular Expression at the begin of the Name with a caret ^
  • use the -f format operator to force two places when inserting the new number
  • use $script:x/$global:x to update a variable inside the rename {script block} about_scopes
    $x = 1
    (Get-ChildItem "[0-9][0-9] *.sql") | 
        Rename-Item -NewName {$_.Name -replace '^\d{2}', ("{0:D2}" -f $global:x++} -WhatIf

If the output looks OK, remove the trailing -WhatIf