CMD "Rename" command - cmd

I want to remove first 21 characters from every ".pdf" file in folder.
My command:
rename "*.pdf" "/////////////////////*.pdf"
The problem remains only the following: The first file is renamed twice. Deletes the first 42 characters. Other files are renamen correctly (21).

This command would do it, but there are many undetected pitfalls. What if the filename does not have more than 21 characters? What if the NewName duplicates an existing filename?
powershell -NoLogo -NoProfile -Command ^
"Get-ChildItem .\*.pdf |" ^
"ForEach-Object { Rename-Item -Path $_.FullName -NewName $($_.Name[21..($_.Name.Length)] -join '') -WhatIf }"

The problem is, that the file mask *.pdf may be "updated" with newly created files during the process.
The same goes for a simple for %%a in (*.pdf) loop.
To work around this, make sure, the list of files gets generated before rename does it's thing:
for /f "delims=" %%a in ('dir /b *.pdf') do rename "%%a" "/////////////////////*.pdf"
The do part is only executed, after the (...) part is done, so newly created/changed files won't be processed a second time.
Same pitfalls as in lit's answer apply:
What if the filename does not have more than 21 characters?
What if the NewName duplicates an existing filename?

Related

How to change extension from en.srt to .srt in command prompt

I have a list of en.srt files in my folder. I need to convert them to .srt extension.
For example
Criminal Minds - 1x01 - Extreme Aggressor.en.srt to Criminal Minds - 1x01 - Extreme Aggressor.srt
Tried the below command and it didn't work,
ren *.en.srt *.srt
Renaming extension like ren *.srt *.srv works. (Changing all files' extensions in a folder with one command on Windows)
Would like to know if there is a workaround for this?
A simply though clumsy method is to rename the files twice – first remove .srt, then change .en to .srt (given that there are no other files *.en):
ren "*.en.srt" "*." & ren "*.en" "*.srt"
A more elegant solution is the one provided by user Mofi in his comment:
#for /F "eol=| delims=" %I in ('dir "*.en.srt" /B /A:-D 2^> nul') do #for %J in ("%~nI") do #ren "%~I" "%~nJ%~xI"
In a batch-file this code would look similar to this (note the necessarily doubled %-signs):
#echo off
rem // Loop through all matching files:
for /F "eol=| delims=" %%I in ('dir "*.en.srt" /B /A:-D 2^> nul') do (
rem /* There are `~`-modifiers for `for` meta-variables that allow to split file names:
rem `~n` returns the base name, so the (last) extension becomes removed;
rem `~x` returns the extension (including the leading `.`);
rem therefore, `%%~nI` is the original file name with `.srt` removed, hence
rem ending with `.en`, and `%%~xI` is the original extension `.srt`;
rem another loop is used to also split off `.en` from `%%~nI`: */
for %%J in ("%%~nI") do (
rem /* Now `%%~J` returned the same as `%%~nI`, but `%%~nJ` removes `.en`;
rem so finally, rename the file to `%%~nJ` plus the original extension `.srt`: */
ren "%%~I" "%%~nJ%%~xI"
)
)
Following the thorough thread How does the Windows RENAME command interpret wildcards? on Super User, I found out that there is a way using a single ren command:
ren "*.en.srt" "?????????????????????????????????????????.srt"
However, you need to make sure to have enough ?, namely as many as there are characters in longest matching file name without .en.srt; otherwise, file names become truncated. You can avoid truncation by replacing the same sequence of ? instead of *, so longer file names are not renamed at all:
ren "?????????????????????????????????????????.en.srt" "?????????????????????????????????????????.srt"
Anyway, this only works when the original file names do not contain any more . besides the two in .en.srt; otherwise, everything behind the first . becomes removed and (finally replaced by srt).
Not difficult in PowerShell to identify the files and replace the end of the filename with a regex. When you are confident that the files will be renamed correctly, remove the -WhatIf from the Move-Item command.
powershell -NoLogo -NoProfile -Command ^
"Get-ChildItem -File -Path '.' -Filter '*.en.srt' |" ^
"ForEach-Object {" ^
"Move-Item -Path $_.FullName -Destination $($_.FullName -replace 'en.srt$','srt') -WhatIf" ^
"}"
Of course, it would be easier if the command shell were PowerShell. BTW, this exact same code would work on Linux and Mac without change.
Get-ChildItem -File -Path '.' -Filter '*.en.srt' |
ForEach-Object {
Move-Item -Path $_.FullName -Destination $($_.FullName -replace 'en.srt$','srt') -WhatIf
}
I don't have a cmd at my disposition but I would guess that
ren *.en.srt *.tmp
ren *.tmp *.srt
works

cmd Search for files from list of partial filenames then copy to folder

I have a text file list of approx 120,000 filenames. Many of the files on the list are in a folder or it's subfolders, but with slight variations on the filenames.
so I want to search using the list of partial filenames and copy the matches to another folder.
Each line on the list is a name and a title separated by a bar for example:
A Name|The Title
John Smith|A Life
The files are various text formats and all have extra stuff in the filenames like:
A Name - The Title V1.4 (html).lit
John Smith - A Life: Living on the Edge [MD] (pdf).rar
I've tried the code from this thread
and this thread but neither are finding any of the files. Can anyone help please.
This PowerShell script assumes that if both the first field "name" and the second field "title" are anywhere in the filename that it should be copied. When you are confident that the correct files will be copied, remove the -WhatIf from the Copy-Item command.
Note that this does not address the issue of multiple files with the same name.
If you wanted to require the "name" field to be at the beginning of the string, you could add it to the match expression. $_.Name -match '^'+$pair.name. If you want the matches to be case sensitive, use -cmatch.
$sourcepath = 'C:\src'
$targetpath = 'C:\other'
$searchpairs = Import-Csv -Header "name","title" -Delimiter "|" -Encoding ASCII -path .\mdb.txt
foreach ($pair in $searchpairs) {
Get-ChildItem -Recurse -File -Path $sourcepath |
Where-Object { ($_.Name -match $pair.name) -and ($_.Name -match $pair.title) } |
ForEach-Object { Copy-Item $_.FullName $targetpath -WhatIf}
}
Adjust the paths and you should be good with this one:
#ECHO OFF
REM **************************************************
REM Adjust location of list
SET list=C:\adjust\path\list.txt
REM Source dir
SET source=C:\adjust\path\source
REM Target dir
SET destination=C:\adjust\path\destination
REM **************************************************
FOR /F "tokens=1,* delims=|" %%A IN (%list%) DO (
ECHO.
ECHO %%A - %%B
CALL :copy "%%A - %%B"
)
ECHO.
ECHO Done^!
PAUSE
EXIT
:copy
FOR /R "%source%" %%F IN (*) DO (
ECHO "%%~nF" | FINDSTR /C:%1 >nul && COPY "%%~fF" "%destination%\%%~nxF" && EXIT /B
)
EXIT /B
Be aware: this requires the scheme in list.txt to be A|B and the scheme of every file to be copied *A - B* (including spaces) while * may be no or any character(s).
Might not be the solution you are looking for, but I ditched batch scripting years ago. I use Powershell instead, and simply call the Powershell script from batch file.
Here is the code in case you are interested,
searchfiles.ps1
$searchStrings = #("city", "sniper") # Declare an array to iterate over.
foreach ($string in $searchStrings) {
Get-ChildItem -Path D:\Movies\Movies | ? { $_ -match $string }
}
And now call the Powershell script from batch file.
searchfiles.bat
Powershell.exe -ExecutionPolicy RemoteSigned -Command "& searchfiles.ps1 -Verb RunAs"
Hope it helps!
That's not to say I don't use batch scripting at all. I will use them only for simpler operations, like calling another script, or opening a folder, etc. With Powershell, I love taking the help of the underlying .NET framework and sweet piping!

Replace multiple file name inside folder in Windows Batch. The code must be in one line only

I got difficulties in replacing multiple file names.
The scenario would be :
[Before]
C:¥data¥
-HOSTNAME1_20170921_5555.zip
-HOSTNAME2_20170921_5555.zip
-HOSTNAME3_20170921_5555.zip
[After]
C:¥data¥
-HOSTNAME1_20170908_5555.zip
-HOSTNAME2_20170908_5555.zip
-HOSTNAME3_20170908_5555.zip
I tried the below command but not getting satisfied result.
RENAME C:¥data¥*20170921_5555.zip *20170908_5555.zip
Unfortunately the result was:
C:¥data¥
-HOSTNAME1_20170920170908_5555.zip
-HOSTNAME2_20170920170908_5555.zip
-HOSTNAME3_20170920170908_5555.zip
Anyone can solve the problem?
and tell me why the above code was not working as expected.
You specifically require a single line, so here is a powershell version.
get-childitem *20170921_5555.zip | foreach { rename-item $_ $_.Name.Replace("20170921_5555", "20170908_5555") }
Use a for to iterate the files with the wrong date
a 2nd stacked for /f to split the name at the _ and
rename replacing the 2nd element with the proper date
With one single cmd line:
> #for %A in (*_20170921_*.zip) do #for /f "tokens=1,2* delims=_" %B in ("%A") do #echo ren "%A" "%B_20170908_%D"
ren "¥data¥-HOSTNAME1_20170921_5555.zip" "¥data¥-HOSTNAME1_20170908_5555.zip"
ren "¥data¥-HOSTNAME2_20170921_5555.zip" "¥data¥-HOSTNAME2_20170908_5555.zip"
ren "¥data¥-HOSTNAME3_20170921_5555.zip" "¥data¥-HOSTNAME3_20170908_5555.zip"
If the output looks OK remove the echo in front of the ren command.
If used in a batch file the percent signs have to be doubled %%
BTW you could also use this Powershell script from batch:
powershell -NoP -C "gci '*_20170921_*.zip'|rni -NewName {$_.Name -replace '_20170921_','_20170908_'} -WhatIf
If the output looks OK, remove the trailing -WhatIf

Batch or Bash to remove a timestamp in thousands of files [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I made a major mistake today in handling my selfhosted backup system and wound up deleting about half of my user folder. Luckily, the backup existed and was able to copy all of my data over. The bad part is each file that was restored has a timestamp in the filename.
So a file that was filename.file is now filename~20170401-1999.file
I'm not too bright when it comes to batch files or what not, but is there any way a BAT could be programmed to run through every single filename and take out the timestamp? Every single timestamp starts with the ~ and ends with the period of the filetype. So removing everything including and after the tilde and stopping at the character before the period would fix the problem.
There are some 4600 files needing fixed with a wide variety of filetype extensions. I am on Windows 10 Pro and able to user powershell or bash to fix the error. I have the Windows Linux Subsystem installed, so a bash script is also acceptable.
PowerShell offers a simple solution:
Get-ChildItem -Recurse -File -Filter *~* |
Rename-Item -NewName { $_.Name -replace '~[^.]+' } -WhatIf
-WhatIf previews the renaming operations; remove it, once you've confirmed that the command will work as intended.
For simplicity I've made the assumption that any filename containing ~ must be renamed; the matching can be refined, if false positives must be eliminated:
Get-ChildItem -Recurse -File *~[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9].*
Matching is limited to files (-File), located anywhere in the current directory's subtree (-Recurse).
To only match files located directly in the current directory, remove -Recurse.
The script block ({ ... }) passed to the Rename-Item cmdlet's -NewName parameter calculates the new filename:
$_.Name returns the input file's name ($_ is PowerShell's automatic variable for representing the input object at hand).
-replace '~[^.]+' performs a regex-based string replacement: '~[^.]+' matches a ~ followed by any nonempty sequence (+) of characters other than . ([^.]).; not specifying a replacement string implicitly uses the empty string, so that the matching part is effectively removed from the name.
Just some idea from the top of my head.
You can iterate over the files, and for each filename, you can replace the sub-string that match the regex /~\d+-\d+/ with "" (i.e., empty string) and use the modified string as the file's new name.
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
FOR /f "delims=" %%a IN (
'dir /b /s /a-d "%sourcedir%\*" '
) DO (
FOR /f "tokens=1,2delims=~" %%p IN ("%%~na") DO (
IF "%%q" neq "" ECHO(REN "%%a" "%%~p%%~xa"
)
)
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
The required REN commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(REN to REN to actually rename the files.
Perform a directory scan with subdirectories in basic form withot directornames and assign to %%a. Then tokenise the name part of the full name found into %%p and %%q using ~ as a delimiter. If the second token is not empty then we have a timestamp in %%q so form the new filename from the part in %%p and the extension from %%a
variation of mklement0 without regex
Get-ChildItem -Recurse -File -Filter *~*.file |
rename-item -NewName {"{0}{1}" -f ($_.BaseName -split "~")[0], $_.Extension } -WhatIf
a short version:
gci -Rec -File -Filter *~*.file | ren -n {"{0}{1}" -f ($_.Base -split "~")[0], $_.Extension } -WhatIf

Batch renaming with forfiles, or potentially Powershell

I have an issue when trying to bulk rename files within folders using forfiles and Powershell. The issue I am having is I need to search for files with _T_ in them, so I use the search notation *_T_*.cr2 as they are all RAW files. In a given folder there will be 143 or so RAW files, 69 of them will have _T_ in their names and the rest don't. What I want to achieve is run a quick command that weeds out all files with _T_ in them and then adds an extra _ before the file.
So before: Ab01_T_gh.cr2 and after _Ab01_T_gh.cr2
My issue is that searching for the _T_ files causes the command to keep executing over and over and over, so the file eventually looks like _____________Ab01etc until it hits the Windows file name limit.
Here's what my forfiles command looks like:
forfiles /S /M *_T_*.cr2 /C "cmd /c rename #file _#file"
It works but it works a little too well.
I also tried Powershell with the same result.
Get-ChildItem -Filter "*_T_*.cr2" -Recurse | Rename-Item -NewName { "_" + $_.Name}
Perhaps there's a way I could split up the "find" and "rename" parts of the code? Any help would be greatly appreciated! I can't manually separate out the _T_ files as it would be very time intensive as each parent folder will sometimes have 75 subfolders with 143 RAW files in each.
This works fine:
#echo off
setlocal EnableDelayedExpansion
for %%a in (*_T_.cr2) do (
set z=%%a
set z=!z:~,1!
if not !z!==_ rename %%a _%%a
)
I had to drop forfiles since I could not work with the # variables (maybe with findstr).
I resorted to a simple for loop on the pattern, and only rename if not already starts by underscore.
Recursive version:
#echo off
setlocal EnableDelayedExpansion
for /R . %%a in (*_T_.cr2) do (
echo %%~na%%~xa
set z=%%~na
set z=!z:~,1!
if not !z!==_ rename %%a _%%~na%%~xa
)
Here's a PowerShell version based on your original code:
Get-ChildItem -Filter "*_T_*.cr2" -Recurse |
Where-Object { $_.Name.Substring(0,1) -ne '_' } |
Rename-Item -NewName $("_" + $_.Name)

Resources