Command Prompt Replace a String in the Middle of Filenames - windows

I have a folder with hundreds of files in the following format:
20210322 - Filename description.txt
20210321 - Filename description.txt
20210320 - Filename description.txt
20210319 - Filename description.txt
20210318 - Filename description.txt
...
Using the Windows Command Prompt, how can I rename them to this format:
20210322 Filename description.txt
20210321 Filename description.txt
20210320 Filename description.txt
20210319 Filename description.txt
20210318 Filename description.txt
...
In other word replace, replace " - " with " ".
In the past, I've used
rename "IMG_*.jpg" "////*.jpg"
To remove "IMG_" from the beginning of filenames. I tried to do something similar, but it didn't work:
rename "* - *.txt" "*/ /.txt"

I found a better solution that works for me. One line, no batch file required. Using Windows Power Shell, enter:
Get-ChildItem -Recurse | ` Where-Object { $_.Name -match " - " } | ` Rename-Item -NewName { $_.Name -replace " - ", " " }
The above command will replace the given text in all filenames, including subfolders and subfiles (recursively).
I hope it's able to help someone.

This is easy enough using a language that is already on supported Windows systems. The -replace will remove the ' - '. When you are satisfied that the files will be renamed correctly, remove the -WhatIf from the Rename-Item command.
powershell.exe -NoLogo -NoProfile -Command ^
"Get-ChildItem -Path '.' -Filter '*.txt' |" ^
"ForEach-Object {" ^
"Rename-Item -Path $_.FullName -NewName $($_.Name -replace ' - ',' ') -WhatIf" ^
"}"
It is easier when run from a PowerShell console or as a .ps1 script.
Get-ChildItem -Path '.' -Filter '*.txt' |
ForEach-Object {
Rename-Item -Path $_.FullName -NewName $($_.Name -replace ' - ',' ') -WhatIf
}
To get a "one-liner," put the first code example above into a file such as Do-Rename.bat saved in a directory mentioned in your PATH variable. Then use a command such as:
Do-Rename

Related

How do I find and replace a character in filenames in Windows 10 using command line?

I want to replace all the underscore characters (_) with a space ( ) in a filename.
How can I do this quickly, when I have lots of _ characters to replace?
You can use PowerShell's Rename-Item command:
Get-Item .\path\to\file_name_with_underscores.txt |Rename-Item -NewName {$_.Name.Replace("_", " ")}
You can do this for multiple files at once if desired:
# all relevant files in the current folder
Get-ChildItem . -File -Filter *_* |Rename-Item -NewName {$_.Name.Replace("_", " ")}
# all relevant files in the current folder and all subfolders
Get-ChildItem . -File -Recurse -Filter *_* |Rename-Item -NewName {$_.Name.Replace("_", " ")}

Batch Replace Character in File Names

I have about 600 video files with the $ special character in the title.
I want to batch replace this with a letter s.
I found the powershell code online below and it works fine with replacing letters with other letters but fails when trying to replace the $ special character
get-childitem -recurse | rename-item -newname { $_.name -replace "",""}
I tried using the code below and it ends up adding an s to the end of the file type instead of replacing the $
get-childitem -recurse | rename-item -newname { $_.name -replace "$","s"}
$hortvid.mp4 becomes $hortvid.mp4s instead of shortvid.mp4
Any ideas on how to get this to work correctly?
Just use \ escape character:
When running line in the directory:
get-childitem -recurse | rename-item -newname { $_.name -replace "\$","s"}
input file:
$hortvid.mp4
output file is renamed:
shortvid.mp4
$ is used for specify variable in powershell. And a string with double quote is evaluate in powershell like this :
$variable1="Hello"
$variable2="$variable1 world"
$variable2
if you dont want evaluate a character into a double quote string, you can backslash you caractere like the proposed solution of #lww. Or simply, you can use simple quote.
Like this :
Get-ChildItem -recurse | Rename-Item -Newname { $_.Name -replace '$', 's'}

How to recursively truncate filenames in powershell?

I need to truncate filenames to 35 characters (including extension) so I run this script and it worked for the directory it self (PowerShell, Windows 10).
Get-ChildItem *.pdf | rename-item -NewName {$_.name.substring(0,31) + $_.Extension}
Then I wanted to apply the same script including subdirectories:
Get-ChildItem -Recurse -Include *.pdf | Rename-Item -NewName {$_.Name.substring(0,31) + $_.Extension}
This script gave me an error like this for each file:
Rename-Item : Error in input to script block for parameter 'NewName'. Exception when calling "Substring" with the arguments "2": "The index and length must reference a location in the string. Parameter name: length"
On line: 1 Character: 62
+ ... *.pdf | Rename-Item -NewName {$_.Name.substring(0,31) + $_.Extension}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (C:\User\prsn..._file_name_long.pdf:PSObject) [Rename-Item], ParameterBindingException
+ FullyQualifiedErrorId : ScriptBlockArgumentInvocationFailed,Microsoft.PowerShell.Commands.RenameItemCommand
I tried this one but it doesn't go on subdirectories:
Command to truncate all filenames at 255 characters
I found this one but it doesn't have an answer:
https://superuser.com/questions/1188711/how-to-recursively-truncate-filenames-and-directory-names-in-powershell
I don't think you can use $_ that way. I think you have to wrap it in a ForEach loop in order to get the references to work that way. Once that's done, you'll have to specify the path of the file you want to rename as well:
Something like:
Get-ChildItem -Recurse -Include *.pdf -File |
ForEach-Object{
Rename-Item -Path $_.FullName -NewName ( $_.BaseName.SubString(0, 31) + $_.Extension )
}
Notice I used parenthesis instead of curly braces. If you use a script block it may not evaluate. There are other ways to make it happen, but I think using parens is the most obvious.
Notice I used $_.BaseName instead of name. Base name doesn't include the extension. though I don't know how your sub-string works out I left it in for you decide.
You can combine this with #Mathias's answer or some modification of it. That might give you a better or more reliable way to derive the new file name. I haven't tested it, but it might look something like:
Get-ChildItem -Recurse -Include *.pdf -File |
ForEach-Object{
Rename-Item -Path $_.FullName -NewName ( ($_.Name -replace '(?<=^.{35}).*$') + $_.Extension )
}
Use the -replace regex operator to remove anything after the first 35 chars - it will simply ignore any string that doesn't have at least 35 characters and return it as-is:
$_.Name -replace '(?<=^.{35}).*$'
The correct error message is
Exception calling "Substring" with "2" argument(s): "Index and length must refer to a location within the string.
The reason is that the second argument is greater than the length of the file name. e.g. "abc".Substring(0,4) throws.
Answer
$renameTarget = dir -File -Recurse *.pdf | ? { $_.Name.Length -gt 35 }
$renameTarget | Rename-Item -NewName {
$_.name.substring(0, 31) + ".pdf"
}
or
dir *.pdf -File -Recurse | Rename-Item -NewName {
$_.name.substring(0, [Math]::Min($_.BaseName.length, 31)) + ".pdf"
}

How to remove character from files in folder in command?

I have windows 7
I have a folder name employeephotos about 100 pictures that all have name_last.
I would like to remove all the "_" from the files in the folder and make the files namelast.jpg.
I have try this command
PS U:\desktop\employeephotos> Dir | Rename-Item -NewName { $_.name replace"_",""}
Rename-Item : Source and destination path must be different.
At line:1 char:18
+ Dir | Rename-Item <<<< -NewName { $_.name -replace"_",""}
+ CategoryInfo : WriteError: (U:\desktop\employeephotos\New folder:String) [Rename-
+ FullyQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.RenameItemCommand
(From my comments)
Rename-Item is a PowerShell command, so you need to be working in PowerShell instead of the cmd.exe command prompt.
It might be picking up files with no _ in the name, the rename does not change the name, and they cannot be given the same name, so it fails. Try dir *_* at the start to only find and rename files with _ in the name.
You might try something like this:
Get-ChildItem -Filter "*_*" | Foreach-Object { Rename-Item -Path $_.Name -NewName $_.Name.Replace("_", "") -WhatIf }
If it produces the output you're looking for, then just pull the -WhatIf parameter off.

How can I bulk rename files in PowerShell?

I'm trying to do the following:
Rename-Item c:\misc\*.xml *.tmp
I basically want to change the extension on every files within a directory to .tmp instead of .xml. I can't seem to find a straight forward way to do this in PowerShell.
From example 4 in the help documentation of Rename-Item retrieved with the command:
get-help Rename-Item -examples
Example:
Get-ChildItem *.txt| Rename-Item -NewName { $_.Name -replace '\.txt','.log' }
Note the explanation in the help documentation for the escaping backslash in the replace command due to it using regular expressions to find the text to replace.
To ensure the regex -replace operator matches only an extension at the end of the string, include the regex end-of-string character $.
Get-ChildItem *.txt | Rename-Item -NewName { $_.Name -replace '\.txt$','.log' }
This takes care of the case mentioned by #OhadSchneider in the comments, where we might have a file named lorem.txt.txt and we want to end up with lorem.txt.log rather than lorem.log.log.
Now that the regex is sufficiently tightly targeted, and inspired by #etoxin's answer, we could make the command more usable as follows:
Get-ChildItem | Rename-Item -NewName { $_.Name -replace '\.txt$','.log' }
That is, there is no need to filter before the pipe if our regex sufficiently filters after the pipe. And altering the command string (e.g. if you copy the above command and now want to use it to change the extension of '.xml' files) is no longer required in two places.
This works well too when you're in the desired directory.
Dir | Rename-Item –NewName { $_.name –replace "old","new" }
The existing answers suggest the -replace operator, but what if the file is called a.xml.xml? Both .xml substrings will be replaced and the end result would be a.tmp.tmp. Fortunately, there's a .NET method for this:
Dir *.xml | rename-item -newname { [io.path]::ChangeExtension($_.name, ".tmp") }
(Manish Kumar was close with GetFileNameWithoutExtension but this is more elegant and probably a bit more efficient, not that it overly matters in this case)
Here's another variant that will work.
dir *.xml | Rename-Item -NewName {$_.BaseName + ".tmp"}
$_.BaseName will do the "base" name without the (last) extension.
a shortened version using the alias would be:
ls *.xml | ren -new {$_.BaseName + ".tmp"}
dir -Recurse | where-object -FilterScript {$_.Extension -eq ".xml"} | Rename-Item -NewName {[System.IO.Path]::GetFileNameWithoutExtension($_.fullname) + ".tmp"}
use -WhatIf to evaluate the result first
Even easier - remember that the replace search string is a regular expression,
dir *.xml | rename-item -newname {$_.name -replace "xml$","tmp"}
The "$" represents end-of-string, so the characters "xml" must be the last three chars of the filename.
This seems to work and is a pythonic i.e simple is better than complex (https://www.python.org/dev/peps/pep-0020/) way of doing it (once you are in the directory):
$files = Get-ChildItem -file -Filter *.xml;
ForEach ($file in $files)
{
$n = $file.Basename
Copy-Item -Path $file -Destination "$n.tmp"
Remove-Item "$n.xml"
}

Resources