Reputation: 447
I'm trying to find a solution to strip some dates out of filenames programmatically. My files have the following format:
net_20110909_servercleanup.pdf
or
net_servercleanup_20110909.pdf
I've used the solution posted below (found on Stack Overflow also) to update some of the filenames but I would ideally have one solution that could update all files in my directories. I'd like to strip the date and one of the underscores out so the final file looks like this:
net_servercleanup.pdf
I'd like to do this from a batch file or PowerShell. I've seen some solutions that accomplish something like this using RegEx but I don't know enough about them to create something that will work. Any suggestions on how to accomplish this?
$filelist = (get-childitem c:\folder | Where-Object {$_.mode -match "a"} | foreach-object {$_.name})
foreach ($file in $filelist)
{
$len = $file.length
$newname = $file.substring(0,$len -13)
$newname = $newname + '.txt'
Rename-Item C:\folder\$file $newname
clear-variable newname, len
}
Upvotes: 1
Views: 3782
Reputation: 70923
As this is also tagged as batch,
This code uses a for /f
command to remove the numbers and underscores from the filename, keeping the first and second remaining elements joined with an underscore and then renames the file.
@echo off
setlocal enableextensions disabledelayedexpansion
for /r "c:\some\folder" %%f in ("net_*.pdf"
) do for /f "tokens=1,2 delims=_0123456789" %%a in ("%%~nf"
) do echo ren "%%~ff" "%%a_%%b%%~xf"
For testing, ren
command is prefixed with a echo
command. If the output is correct, remove the echo
Of course, if more than a matching file is found inside a folder, as it is impossible to have two files with the same name inside the same folder, the rename operation will fail for second or later files inside the same folder.
Upvotes: 1
Reputation: 3275
PowerShell, untested but should work:
$filelist = Get-ChildItem C:\folder | Where-Object {$_.Mode -match "a"} `
| Foreach-Object {$_.FullName}
foreach ($fullpath in $filelist)
{
$newpath = $fullpath -replace "_(19|20)[0-9]{6}"
Rename-Item -Path $fullpath -NewName $newpath -WhatIf
}
The _(19|20)[0-9]{6}
regular expression matches the following pattern: leading "_" followed by "19" or "20" and then any six digits. If you have file names where date does not strictly match your example, you may need to modify the regex to catch them all.
The -WhatIf
switch allows you to do a "dry run" i.e. test cmdlets like Remove-Item without actually performing any file operations. Remove it when everything looks OK and you are ready to proceed with actual renaming.
Upvotes: 1
Reputation: 10347
try this regex:
_\d{8}
and replace with empty
. this matchs _20110909
in
net_20110909_servercleanup.pdf
or net_servercleanup_20110909.pdf
and result is net_servercleanup.pdf
.
Upvotes: 1
Reputation: 4081
If you know that your filenames will always be of the form you mentioned you can just remove the underscore and 8 digits. Try this:
get-childitem c:\folder | Where-Object {$_.mode -match "a"} | foreach-object {
rename-item $_.FullName ($_.FullName -replace '_\d{8}') -WhatIF
}
Remove the -whatif to actually perform the rename. the -replace parameter takes a regex that matches an underscore followed by 8 digits. Since you do not specify what to replace the match with, it is replaced with an empty string.
Note that this renames all of the files to the same filename causing Rename-Item to error if the file exists. If these are in nested subfolders and you want to iterate through them all you need to add a -Recursive parameter to get-childitem.
Upvotes: 1
Reputation: 499
I don't know what that language(?) is, but in C++, I'd do it by separating it into pieces based on your separator (this case, an underscore). Basically, I'd get the substring from the start to the character before the first underscore, store it into a stream (stringstream to be exact), get substring from the character after the first underscore to the character before the second underscore, ... , and so on. and then from the stream, I'd get the pieces one by one and check if it is an integer, if it is an integer then I discard it, otherwise it is appended to a string, if the string is not empty then I append a separator (an underscrore) before adding the piece.
I could write the code in c++ but I'm not sure if that would help
Upvotes: 1