Teeoney
Teeoney

Reputation: 131

How to rename multiple files with existing Unix time in file name?

While I know how I would do this in PHP, it doesn't make sense to install IIS, install PHP just to get this done.

I have a folder D:\Data that has several subfolders in it. These folders contain files which are backups created with a program that adds a time stamp to the name to allow multiple copies of the file to be backed up.

These files need to be named:

usera.dat

But they are named currently:

usera.dat.17383947323.dat  

In PHP, I would load the file name into a string, explode the string on ".", then rename the file using the [0] and [3] elements to rename the file, i.e. without the loop to read the directories:

$filename = $existing_file
$explodename = explode(".",$filename);
$newfilename = $explodename[0] . "." . $explodename[3];
rename($filename, $newfilename);

Does anyone have any recommendation on how to do this with PowerShell or a batch file looping over all the subfolders in D:\Data?

Right now I am manually editing each file removing the extra Unix time stamp.dat part.

Upvotes: 1

Views: 109

Answers (3)

Mathias R. Jessen
Mathias R. Jessen

Reputation: 174690

Translating this from PHP to PowerShell should be a breeze, let's give it a try:

$files = Get-ChildItem -Filter *.dat.*.dat

foreach($file in $files){
    $filename = $file.Name
    $explodename = $filename.Split('.')
    $newfilename = "$($explodename[0]).$($explodename[3])"
    Rename-Item $file.FullName -NewName $newfilename
}

As shown above:

  • PowerShell does not have an explode() function, but we can use the String.Split() method on any string and get a string array back
  • . is not a string concat operator in PowerShell, but we can use subexpressions $(...) inside an expandable string.
  • The Rename-Item cmdlet will take care of renaming

A more PowerShell-idiomatic solution would be to leverage the pipeline though:

Get-ChildItem -Filter *.dat.*.dat | Rename-Item -NewName {$explodename = $_.Name.Split('.');"$($explodename[0]).$($explodename[3])"}

You could also use a regex pattern in place of the Split() method and string concatenation:

Get-ChildItem -Filter *.dat.*.dat | Rename-Item -NewName {$_.Name -replace '^([^\.])\..*\..*\.([^\.])$','$1.$2'}

Or do the concatenation with the -join operator:

Get-ChildItem -Filter *.dat.*.dat | Rename-Item -NewName {$_.Name.Split('.')[0,3] -join '.'}

Whatever you fancy, Get-ChildItem and Rename-Item are definitely the commands you'd want to use here

Upvotes: 2

Magoo
Magoo

Reputation: 80113

One-liner in batch from the prompt:

@FOR /r "U:\sourcedir" %a IN (*) DO @FOR %b IN ("%~na") DO @FOR %c IN ("%~nb") DO @IF "%~xc" neq "" ECHO REN "%a" "%~nxc"

Note: echoes the rename command for testing. Remove the echo keyword after testing to execute the rename.

I used u:\sourcedir as a test directory.

Translation: for each filename in the subtree (%%a) take the name part only and assign to %%b, repeat for %%c and if there was no extension part in the result, then do the rename.

Upvotes: 1

mklement0
mklement0

Reputation: 439193

Mathias R. Jessen's answer contains many helpful pointers, but it seems that the simpler and more robust approach would be to simply drop the final 2 extensions, assuming that all files in the folder tree have these 2 extraneous extensions:

Get-ChildItem -File -Recurse D:\Data |
  Rename-Item -NewName { $_.Name -replace '(\.[^.]*){2}$' }

Upvotes: 0

Related Questions