Regular Expression in a Windows Batch File - regex

I'm looking for way to rename multiple files with a batch job.
Yes, I know there are many Applications around which can achieve this.
But I need an automated way, something like a Batch File which I can call from a Scheduler (SOS Job Scheduler). We need to rename hundreds of files daily!
The Goal is to set the 17-25 charcaters at the beginning of the file.
00010028229720270014468393_TB-E.pdf -> 00144683930001002822972027_TB-E.pdf
000100282297202700144683931ESR-AF.pdf -> 001446839300010028229720271ESR-AF.pdf
00010031141040250016353371ESR-AF.pdf -> 00163533700010031141040251ESR-AF.pdf
0001003167580004001667217KTO.pdf -> 0016672170001003167580004KTO.pdf
Here an example which is more clearer:
0001 002822972 027 001446839 _TB-E .pdf -> 001446839 0001 002822972 027 _TB-E .pdf

#ECHO OFF
SETLOCAL
SET "sourcedir=c:\sourcedir"
FOR /f "delims=" %%a IN (
'dir /b /a-d "%sourcedir%\*" '
) DO (
SET "name=%%a"
CALL :transform
)
GOTO :EOF
:transform
ECHO REN "%sourcedir%\%name%" "%name:~16,9%%name:~0,16%%name:~25%"
GOTO :eof
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.
Note that the very first example you've presented has ...393_TB-E... in the transformed version, that 3 is missing.

This can be accomplished very simply with the help of REPL.BAT - a hybrid JScript/batch utility that performs a regex search and replace on each line from stdin and writes the result to stdout. The utility uses only native scripting capabilities that are available to any modern Windows machine from XP onward; no 3rd party executable required. Complete documentation is embedded within the script.
Assuming REPL.BAT is somewhere within your PATH:
#echo off
pushd "c:\sourcePath"
for /f "delims=" %%A in (
'dir /b /a-d *.pdf ^| repl "(.{16})(.{9}).*" "ren \q$&\q \q$2$1*\q" x'
) do %%A
popd
Using only native batch commands, without any CALL:
#echo off
setlocal disableDelayedExpansion
pushd "c:\sourcePath"
for /f "delims=" %%F in ('dir /b /a-d *.pdf') do (
set "file=%%F"
setlocal enableDelayedExpansion
ren "!file!" "!file:~16,9!!file:~0,17!*"
endlocal
)
popd
If you know that none of your file names contain the ! character, then you can simply enable delayed expansion at the top, and remove both SETLOCAL and ENDLOCAL from within the loop.
Both solutions above rely on the fact that * at the end of the target name will preserve the remainder of the original file name. See How does the Windows RENAME command interpret wildcards? for more info.

(\d{16})(\d+)(.*?\.pdf) -> \2\1\3
{16} means you take 16 repetitions (of a digit)

Related

Modify Robocopy script to read number appended to files in folder, add one, and rename file that is being copied

So I have a very simple script set up on the task scheduler to move screenshots once a day from one folder to another. Thats working fine, but when the screenshots are taken, they are automatically give a name by Steam, e.g. "Screenshot.png", "Screenshot 1.png", "Screenshot 2.png" etc depending on how many are in the folder. So when the files are emptied in to the other folder each day, every set of screenshots taken on that day start again at "Screenshot.png" and go up from there. The result is that when they are moved, they are going to be either overwriting or appending (1) or something (not sure which as haven't had this running yet!)
So I want to change the following batch file to find the highest number in "Screenshot xxx.png" in the destination folder, add one, rename the file in the source folder to this number and then do the move. This will have to fit in a loop so it can go through all files in the source folder.
#echo off
set X=1
set "source=C:\Users\Leigh\AppData\Local\Colossal Order\Cities_Skylines\Screenshots"
set "destination=D:\Leigh\Pictures\SkyLinesScreenshots"
robocopy "%source%" "%destination%" /mov
exit /b
I had a play and found a script to determine which the next number should be, but couldnt get the regex right:
#echo off
setlocal enableextensions disabledelayedexpansion
setlocal enabledelayedexpansion
set "nextFile=0" & for /f "delims=" %%a in ('
findstr /b /r /x
/c:"\bScreenshot\b\s[0-9]+\.png"
') do if %%~na geq !nextFile! set /a "nextFile=%%~na+1"
endlocal & set "nextFile=%nextFile%"
echo Next file will be: %nextFile%
If I get that right I will integrate them together and work out the problem. This is pretty clear what needs doing, so could anyone either give me the correct regex, or even more if they so wish.
Thanks in Advance!
Windows 10 64-bit. PowerShell 5
Archive screenshots to timestamp folder (mmddyy) using CMD and robocopy. Delete archives older than 14 days with PowerShell.
#echo off
setlocal enableextensions
set "source=C:\Users\Leigh\AppData\Local\Colossal Order\Cities_Skylines\Screenshots"
set "destination=D:\Leigh\Pictures\SkyLinesScreenshots\%DATE:~-10,2%%DATE:~-7,2%%DATE:~-4,2%"
robocopy "%source%" "%destination%" /mov
rem delete archives older than 14 days. Remove -whatif
powershell -command "get-childitem "D:\Leigh\Pictures\SkyLinesScreenshots" |? {$_.psiscontainer -and $_.lastwritetime -lt (get-date).adddays(-14)} |% {remove-item $_ -recurse -force -whatif}"
exit /b
You can adjust the age threshold through .adddays. This is in WhatIf mode. Remove -whatif to delete the folders.
Windows 10 64-bit
Count, increment, move w/ rename with Windows 10 64-bit CMD, for, set, and move.
If the source screenshots are created without enough interval this will happen:
Remove the echo when it is working.
CMD:
#rem Count, increment, move w/ rename with Windows 10 64-bit CMD, for, set, and move
cmd /q /v /e
pushd "%HOME%\Pictures\SkyLinesScreenshots"
FOR /f %g in ('dir /a-d ^| find "File(s)"') do set z=%g
cd "%LOCALAPPDATA%\Colossal Order\Cities_Skylines\Screenshots"
FOR /f "delims=" %g in ('DIR /b /a-d') do (
set /a z+=1 > nul
echo move "%g" "%HOME%\Pictures\SkyLinesScreenshots\screenshot!z!.png"
)
popd
exit /b
Script:
#rem Count, increment, move w/ rename with Windows 10 64-bit CMD, for, set, and move
#echo off
setlocal enableextensions
pushd "%HOME%\Pictures\SkyLinesScreenshots"
FOR /f %%g in ('dir /a-d ^| find "File(s)"') do set z=%%g
cd "%LOCALAPPDATA%\Colossal Order\Cities_Skylines\Screenshots"
FOR /f "delims=" %%g in ('DIR /b /a-d') do (
set zname=%%g
Call :increment
)
popd
exit /b
:increment
set /a z+=1 > nul
echo move "%zname%" "%HOME%\Pictures\SkyLinesScreenshots\screenshot%z%.png"
exit /b
Results:

Renaming a list of files #1 by another list of files #2

Renaming a list of files (in one folder) contained in a text file like MyList1.txt by another list of files contained in another text file like MyList2.txt.
I would like to use a Windows command batch file (not PowerShell, script, etc.) which renames a list of files in one folder, contained in a text file, by another list of files contained in another text file.
Suppose I have a list of files inside a text file. These files are in one folder, for example D:\Librarian
File D:\Test\MyList1.txt contains:
Directory.zip
Subject.zip
Penny.zip
Car.zip
Auto.zip
One_Upon_A_time.zip
All is relative.zip
Zen of graphics programming – Corilolis.zip
PC Magazine – July 1999 No.22.zip
Bytes is over with quantum.zip
And I want to replace them by the file names listed in D:\Test\MyList2.txt containing:
Patatoes.zip
Chips.zip
Hot Dogs Sweet.zip
Ice Cream_Very – Good.zip
We must eat to live.zip
Ketchup on potatoes is a muxt.zip
The Magazine are owned by few guys.zip
Desert are not necessary_in life.zip
Sugar_is_a_legal_drug.zip
People-who_don’t-like_pizzas_don’t like bread.zip
So
Directory.zip will become Patatoes.zip
Subject.zip will become Chips.zip
Penny.zip will become Hot Dogs Sweet.zip
etc.
Both MyList1.txt and MyList2.txt have same number of lines (same number of file names).
OS is: Windows 10.
Must use batch (cmd)
One folder - D:\Librarian have files to be renamed.
Another folder have the two files MyList1.txt and MyList2.txt
MyList1.txt contains the list of files from D:\Librarian
MyList2.txt contains the new name of files for D:\Librarian
------Begin 1: dbenham----------------------------------------------------------
I have tried what you wrote and it's working except for 2 file names.
Probably Windows command interpreter doesn't accept some punctuation in these file names.
Here what appear on command prompt (DOS under Windows 10):
(I remove #echo off of course to be able to see that.)
D:\>setlocal disableDelayedExpansion
D:\>pushd "d:\Librarian"
d:\Librarian>(for /F "usebackq eol=: delims=" %F in ("d:\Test\MyList1.txt") do (
set "from=%F"
setlocal enableDelayedExpansion
set "to="
set /p "to="
if defined to ren "!from!" "!to!"
endlocal
) ) 0 (<) d:\Test\MyList2.txt
It's not (<) but only < but for x reason 0< is not visible.
d:\Librarian>(
set "from=Directory.zip "
setlocal enableDelayedExpansion
set "to="
set /p "to="
if defined to ren "!from!" "!to!"
endlocal
)
d:\Librarian>(
set "from=Subject.zip"
setlocal enableDelayedExpansion
set "to="
set /p "to="
if defined to ren "!from!" "!to!"
endlocal
)
...
d:\Librarian>(
set "from=Zen of graphics programming Corilolis.zip"
setlocal enableDelayedExpansion
set "to="
set /p "to="
if defined to ren "!from!" "!to!"
endlocal
)
The system cannot find the file specified.
d:\Librarian>(
set "from=PC Magazine July 1999 No.22.zip""
setlocal enableDelayedExpansion
set "to="
set /p "to="
if defined to ren "!from!" "!to!"
endlocal
)
The system cannot find the file specified.
d:\Librarian>(
set "from=Bytes is over with quantum.zip"
setlocal enableDelayedExpansion
set "to="
set /p "to="
if defined to ren "!from!" "!to!"
endlocal
)
Windows command interpreter doesn't like - character probably in the following file names:
PC Magazine - July 1999 No.22.zip
Zen of graphics programming - Corilolis.zip
But since a lot of my files have the hyphen character, I would like an advice to get the batch file working also for such file names.
Later... After to use CMD to rename all files (inside MyList1.txt and MyList2.txt and in the folder D:\Librarian) all work good.
I think I copy and paste files from this page and so not same characters for all even if - can appear to be - like you say they can be different on console or on web page.
I can't say I understand all what you did (so bright)!
For example why do:
pushd "d:\Librarian"<br>
(<)d:\Test\MyList2.txt
(No () around the <)
I find Windows commands are just extraordinary. Well more to see what people, like you, can do so with so few commands. Just unbelievable!
------End 1: dbenham----------------------------------------------------------
Hope to not bore you ...
Can I do the same if my files are in folder and subfolders?
Suppose my files are distributed in the following folders:
D:\Librarian\
D:\Librarian\S1\
D:\Librarian\Plane\
MyList1.txt
D:\Librarian\Directory.zip
D:\Librarian\Subject.zip
D:\Librarian\Penny.zip
D:\Librarian\S1\Car.zip
D:\Librarian\S1\Auto.zip
D:\Librarian\S1\One_Upon_A_time.zip
D:\Librarian\S1\All is relative.zip
D:\Librarian\Plane\Zen of graphics programming - Corilolis.zip
D:\Librarian\Plane\PC Magazine - July 1999 No.22.zip
D:\Librarian\Plane\Bytes is over with quantum.zip
MyList2.txt
D:\Librarian\Patatoes.zip
D:\Librarian\Chips.zip
D:\Librarian\Hot Dogs Sweet.zip
D:\Librarian\S1\Ice Cream_Very - Good.zip
D:\Librarian\S1\We must eat to live.zip
D:\Librarian\S1\Ketchup on potatoes is a must.zip
D:\Librarian\S1\The Magazine are owned by few guys.zip
D:\Librarian\Plane\Desert are not necessary_in life.zip
D:\Librarian\Plane\Sugar_is_a_legal_drug.zip
D:\Librarian\Plane\People-who_don't-like_pizzas_don't like bread.zip
What I would like is for example:
ren "D:\Librarian\Directory.zip" "D:\Librarian\Patatoes.zip"
ren "D:\Librarian\Plane\Zen of graphics programming - Corilolis.zip" "D:\Librarian\Plane\People-who_don't-like_pizzas_don't like bread.zip"
Renaming a file is trivial, and reading from a single file is simple with FOR /F. The only tricky bit is reading the corresponding line from a second file, which is the same issue when merging two text files. The most efficient solution is to redirect stdin to the 2nd file for an entire block of code. You can then use SET /P to read successive lines
The following script will generally work, but note that no attempt is made to detect or handle name collisions that could result from a rename operation.
#echo off
setloacal disableDelayedExpansion
pushd "d:\Librarian"
<d:\Test\MyList2.txt (
for /f "usebackq eol=: delims=" %%F in ("d:\Test\MyList1.txt") do (
set "from=%%F"
setlocal enableDelayedExpansion
set "to=" %= Clear any existing value =%
set /p "to=" %= Read the next line =%
if defined to ren "!from!" "!to!"
endlocal
)
)

Windows Batch Scripting : Regular Expression Or Statement

#echo off
set out=%~dp0\FileName.txt
(for /r %~dp0 %%F in ((*System1*.txt*) | (*System2*.txt*)) do (if %%~zF GEQ 1 echo %%F)) > %out%
exit /b
I am trying with the above batch file to look at the directory the batch file is in for files containing a certain string and there size is over 0KB.
The problem I am having is with the OR statement.
The Batch file below fulfills your specifications:
#echo off
set out=%~dp0\FileName.txt
rem "am trying with this batch file to look at the directory the batch file is in"
(for /r "%~dp0" %%F in (*System1*.txt* *System2*.txt*) do (
rem "I want all files greater than 0kb to be written out"
if %%~zF GEQ 1 (
rem "Is there a way to just exclude this Filename.txt file?"
if "%%~nxF" neq "Filename.txt" echo %%F
)
)) > "%out%"
exit /b
However, you must note the following points:
The path to the batch file (%~dp0) should be enclosed in quotes in case it may include spaces.
If there are no other files with System, just the desired System1 or System2, then (*System*.txt*) wild-card would be enough.
Usually all files have a size greater than zero bytes. If your system does not regularly create empty files, the related if command is not necessary.
The output filename Filename.txt will never match the given *System*.txt* wild-card, so the last if command is not necessary.
Without further details this is a possible solution using your code as a base:
#echo off
set "out=%~dp0\FileName.txt"
(for /r "%~dp0" %%F in (*System*.txt*) do if %%~zF GTR 0 echo %%F)>"%out%"
exit /b
#echo off
set "out=%~dp0FileName.txt"
(for /r "%~dp0" %%F in (*System1*.txt* *System2*.txt*) do if %%~zF GEQ 1 echo %%F) > %out%
exit /b
for command allow multiple sets of files in the in clause, so, just include them.

Windows batch file name manipulation

Alright, I'm sure this is a bit of a niche question, but I'm hoping someone can help.
The OS we're dealing with is Windows NT 4.0.
What I need to do is create a batch file that reads in all the Jounal.x (where x is a number greater than 0 and less than 32) files in a folder. Then, I need it to rename each file in the format EJ-REG-X.100.
My biggest problem, I think, is I'm a little fuzzy on the variable syntax and regular expressions for DOS. Here's what code I've tried so far
FOR /R %%g IN (C:\testbatch\transfer\Journal.*) DO (set regnum=%%g, ren Journal.* EJ-REG-%regnum%.100)
Let me know if there's any more information I can provide. Thanks!
try this:
for /l %%a in (1,1,31) do (
set "new=00%%a"
setlocal enabledelayedexpansion
set "new=!new:~-3!"
ren "C:\testbatch\transfer\Journal.%%a" "EJ-REG-!new!.100"
endlocal
)
The /R is for récursive search and you don't use it
so remove it
%%g in your loop and BTW regnum contain the full file path
so start to remove the path and the file name to keep only the extension using %%~xg
by doing that regnum will only contain the file extension
so it will be :
FOR /R C:\testbatch\ %%g IN (Journal.*) DO (
set ext = %%~xg
set ext = %ext:. =%
ren %%g EJ-REG-%ext%.100)

Batch file - matching file extensions

Probably far too easy question, but how do I match a file extension such as .jpg while not matching jpg~ (i.e. a jpg that a program has made a local copy of?) My current line is:
for /f %%a in ('dir /b *.jpg') do echo %%~na
But if any program has a copy of one of the files open (and thus has made a .jpg~ file) this regexp will match those too. I found a reference to $ being the 'end of line', but doing this doesn't work at all:
for /f %%a in ('dir /b *.jpg$') do echo %%~na
I don't think it is possible to filter this with just a FOR command (unless you pipe the output of dir to findstr) but in this case, adding a simple if test is all that is needed:
for %%A IN (*.jpg) DO if "%%~xA"==".jpg" #echo %%~A
I think, the problem arises from the short-name representation. (Use dir /X and you can see that xxx.jpg and xxx.jpg~ both have a 8.3 file-name that ends with .jpg.)