I have file(s) in a folder with names like "223.DAT_2017010211315" I want to loop through all the files and rename them to like 223_2017010211315.DAT"
The closest I got to this requirement is as follows. I could just get the first token of the file name.
set "res=223.DAT_2017010211315"
for /f "tokens=1 delims=." %%i in ("%res%") do (set prefix=%%i)
echo %prefix%
pause
Could someone help me through this?
Let's start by iterating the file system. This should search the required files and show them
for %%f in ("*.dat_*") do echo %%f
Now, once we are able to find the files to process we need to separate the name and the extension of the files. That is an easy task as the for replaceable parameters (%%f in previous code) allow the usage of some modifiers to retrieve specific information of the referenced file (see for /? for a full list). We will use %%~nf (the name of the file referenced by %%f) and %%~xf (the extension of the file being referenced by %%f)
for %%f in ("*.dat_*") do echo %%~nf %%~xf
Once we have the two elements, we need to split the extension using the underscore as a delimiter. This will give us two tokens, left and right sides of the underscore. For this for /f is used to process the file extension.
for /f "tokens=1,2 delims=_" %%a in ("%%~xf") do echo %%a %%b
As we are requesting two tokens, the for /f will use the requested replaceable parameter %%a to store the first one, and will create an additional replaceable parameter %%b (next character) to store the second token.
%%~nf %%~xf
[.][................]
223.DAT_2017010211315 = %%f
^..^ ^...........^
%%a %%b
So, for each file in the list, execute the for /f to retrieve the needed information to execute the ren command.
for %%f in ("*.dat_*") do for /f "tokens=1,2 delims=_" %%a in ("%%~xf") do (
echo ren "%%f" "%%~nf_%%b%%a"
)
Note that for debugging purpouses, the ren command is not executed, only echoed to console to check the code behaviour. If the output is correct, remove the echo and run the code again.
#echo off
REM for every file matching the filter do:
for %%f in (*.dat_*) do (
REM disassemble into tree tokens, using . and _ as delimiters:
for /f "tokens=1,2,3 delims=._" %%a in ("%%~f") do (
REM re-assemble in different order:
echo %%a_%%c.%%b
)
)
Just to show an alternative way:
#echo off&setlocal enabledelayedexpansion
pushd "X:\path\to\folder"
for %%A in (*.dat_*) do (
set fname=%%A
Echo ren "%%A" "!fname:.DAT=!.DAT"
)
Popd
If output looks ok, remove the echo
Related
I have went through a lot of guides for it, but havent found a way to do something similar to lets say turn all files in folder, like these files:
djhwu4s_cat_ruhg29.png
397y_dog_j0929_ej93.png
8yhh_owl.png
into these:
_cat.png
_dog.png
_owl.png
So basically removing everything from file names but a list of predefined strings i am searching for. In example above i would define list as "_cat", "_dog", "_owl". I know that each file will have only one of these variables, and there will be only one file with each of them in folder.
Will appreciate any tips on how to achieve that. Thanks in advance!
edit:
Here is what i came up with (with stuff i can understund) and what seems to be working fine now.
#echo off
setlocal enabledelayedexpansion
set v1=_cat-cat
set v2=_cat-owl
set v3=_cat
set v4=_dog
set v5=_owl
set v6=_horse
FOR /L %%a IN (1,1,6) DO (
rem echo %%a
rem echo !v%%a!
FOR /f %%f in ('dir /b /a:-D *!v%%a!.*') DO (
REN %%f !v%%a!.*
)
FOR /f %%f in ('dir /b /a:-D *!v%%a!_*.*') DO (
REN %%f !v%%a!.*
)
)
rem using two passes of this simpler code i can grasp and understund with dot and with underscore
rem after constructed variables value i make sure cat-cat is not recognised as and renamed to cat
rem no matter if im getting file with that variable as the last string before extension or another underscore
rem Gonna test it in combat now
For some reason this stuff doesnt work with files containing spaces and characters like:
"ab’c efg_dog.png"
FOR /L %%a IN (1,1,36) DO (
FOR /f %%f in ('dir /b /l /a:-D *!v%%a!.*') DO (
REN "%%f" "!v%%a!.*"
)
FOR /f %%f in ('dir /b /l /a:-D *!v%%a!_*.*') DO (
REN "%%f" "!v%%a!.*"
)
)
After further testing i have realised the problem starts with the %%f, and not the REN function as i thought. echo %%f before ren gives just the first part of the name to the first space, hence the REN function cant find the file. In case of "ab’c efg_dog.png" after finding the file with dir, the %%f becomes just "ab’c".
edit: After more tests and experiments and adding those "delims" to the code, the echo now shows proper, full names to be renamed, but it replaces that weird ’ character with ' for the REN command and thats why it still cant find the file to rename.
FOR /L %%a IN (1,1,36) DO (
FOR /f "delims=" %%f in ('dir /b /l /a:-D *!v%%a!.*') DO (
echo %%f
echo REN "%%f" "!v%%a!.*"
)
FOR /f "delims=" %%f in ('dir /b /l /a:-D *!v%%a!_*.*') DO (
echo %%f
echo REN "%%f" "!v%%a!.*"
)
)
#ECHO OFF
SETLOCAL
rem The following setting for the directory is a name
rem that I use for testing and deliberately includes spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
PUSHD "%sourcedir%"
FOR /f "delims=" %%e IN ('dir /b /a-d "*_*" 2^nul ^|findstr /v /b "_"') DO (
FOR /f "tokens=2delims=_." %%y IN ("%%e") DO ECHO REN "%%e" "_%%y%%~xe"
)
POPD
GOTO :EOF
For lack of examples, here's a start.
Always verify against a test directory before applying to real data.
Process the list of filenames that match *_*; find those names that do not start _, pick the second string between the delimiters _ and . and rename using that string (in %%y), prefixed by _ and appended with the original extension.
The ren command is simply echoed to the screen for verification. When happy, remove the echo before the ren to actually execute the rename.
I have some files that I would like to sort through and keep the newest file.
I cannot do it by file attributes date modified or created, which I could do no problem.
Here is the naming convention of the files. FileABC_YYYYMMDD.txt
FileABC_20190201.txt
FileABC_20190125.txt
FileABC_20190118.txt
FileABC_20190111.txt
FileABC_20190104.txt
You can see that the date stamp is in the filename itself. These files are generated weekly. So I'd like to have a batch file loop through them and delete all but most currently dated file. I have really searched for how to do this best and I'm not finding much so I need ideas. I prefer a pure cmd solution but I'm open to powershell solutions as well.
What I am trying on my own is to parse out the date with...
#echo off
setlocal enabledelayedexpansion
for /f "tokens=* delims= " %%G IN ('dir/b /a-d "C:\Users\thomas.maus\Documents\Tom\dev\Test Batch Files\dev\sortbyFileDateName\FileABC_*.txt"') do (
set fileName=%%G
Set theDate=!fileName:~8,8!
echo !theDate!
)
Then I want to take those dates somehow from the results of the loop and do something like
if "%theDate%" GEQ "*****not sure what to put here*****" (
del *all the old files, also not sure what to put here*
)
How about this?
#echo off
for /f "skip=1" %%i in ('dir /o-n /b *.txt') do del %%i
If you just want to test it (see what it would delete) first, do:
#echo off
for /f "skip=1" %%i in ('dir /o-n /b *.txt') do echo %%i
If you do not care about the file dates but only the dates in the file names, you could do the following, given that the part FileABC is always the same and does not contain any _ on its own:
pushd "C:\Users\thomas.maus\Documents\Tom\dev\Test Batch Files\dev\sortbyFileDateName" && (
for /F "skip=1 delims= eol=|" %%F in ('
dir /B /A:-D "FileABC_????????.txt" ^
^| sort /R
') do (
del "%%F"
)
popd
)
Although sort /R does alphabetic sorting, this works because of your chosen date format, which ensures that alphabetic order equals alphanumeric one.
We just loop through the files, sorted by date in decending order, then skip the first file, now being the latest:
#for /f "skip=1" %%a in ('dir /b /o-d *.txt') do #echo #del %%a
Important!
This example will only echo the delete command as a safe measure so you do not delete files you should not have. To perform the actual delete, remove #echo from the line.
To understand more about the functions we used, run the following from cmd.exe
for /?
dir /?
As an additional option, just in case the filename prefix changes throughout and only the _YYYYMMDD.txt remains constant, you can still peform the task using that date as it is already alphabetically sortable.
Here's an example:
#Echo Off
Set "SrcDir=%UserProfile%\Documents\Tom\dev\Test Batch Files\dev\sortbyFileDateName"
For /F "Delims==" %%A In ('Set $ 2^>Nul') Do Set "%%A="
Set "_="
For /F Delims^=^ EOL^= %%A In ('Where "%SrcDir%":*_????????.txt 2^>Nul'
) Do Set "_=%%~nA" & Call Set "$%%_:~-8%%=%%A"
If Not Defined _ Exit /B
For /F "Tokens=1* Delims==" %%A In ('Set $ 2^>Nul') Do Set "_=%%B"
For /F Delims^=^ EOL^= %%A In ('Where "%SrcDir%":*_????????.txt^|Find /V "%_%"'
) Do Del /A /F "%%A"
This uses the fact that the Set command will output variables in alphabetical order.
Lines 2 to 4 just define and undefine the variables we will be using.
Lines 5 and 6 is a single line split over two lines for readability. This will set variables using the last eight characters of the files basenames, to the value of the full filename.
Line 7 is included to exit the script, just in case no .txt files with a basename ending with an underscore followed by eight characters were found in the directory set at line 2.
Line 8 is the special one here, it outputs each variable and corresponding value in alphabetical order. The output is set to a variable, which overwrites itself until the loop ends. This means that the newest file, last one alphabetically, is held with the value of the file named with the newest date.
Lines 9 & 10 are once again a single line split over two for readability. This loops over all matching files in the directory again and uses the Find command to exclude outputting the one which matches that held in the variable as the file with the newest date. Each file output is simply deleted using the Del command.
Please note that this script assumes you only have a single file with each date, as you've only stated that the files are generated weekly.
I have a directory of academic papers that were named using the convention below:
Author1-(Year)-Title.pdf
For example,
Jones-(2011)-XXX.pdf
Smith-(2002)-YYY.pdf
Johnson-(2015)-ZZZ.pdf
I would like to rename them as
(2011)-Jones-XXX.pdf
(2002)-Smith-YYY.pdf
(2015)-Johnson-ZZZ.pdf
That is, to extract the year from the file name and put it in front.
I tried the following code, which did not work
Setlocal enabledelayedexpansion
Set "Year=2013"
Set "Replace="""
For %%a in (*.pdf) Do (
Set "NewName=(%year%)-%%~a"
Ren "%%a" "%NewName%-File:%Year%=%Replace%!"
)
Pause&Exit
In case XXX also contains hyphens I'd suggest using tokens=1,2* to stop parsing the remainder of the file name.
I'd also remove the parentheses, when the year is first place there is no need to further emphasize it.
#Echo off
for /f "tokens=1-2* delims=-()" %%A in (
'Dir /b "*-(*)-*.pdf"'
) do Ren "%%A-(%%B)-%%C" "%%B-%%A-%%C"
Sample output
> dir /b
2002-Smith-YYY.pdf
2011-Jones-XXX.pdf
2015-Johnson-ZZZ.pdf
Not tested
for /f "tokens=1,2,3 delims=-" %%a in ('dir /b "*.pdf"') do (
echo ren "%%a-%%b-%%c" "%%b-%%a-%%c"
)
this will only echo the intended rename command.If it looks ok remove the echo word.
Derived form this SO article - it works:
#ECHO OFF &SETLOCAL ENABLEDELAYEDEXPANSION
FOR %%x IN (*.pdf) DO (
FOR /f "tokens=1-3 delims=-" %%a IN ("%%~x") DO (
SET "Author=%%a"
SET "Year=%%b"
SET "Title=%%c"
ren %%x !Year!-!Author!-!Title!
)
)
Here is a reliable way of doing what you are asking for even if the author part contains - on its own. The title portion may even contain ( and ), but the author part must not. So this is the code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_FILES=.\*-(????)-*.pdf" & rem // (basic pattern to match correct files)
set "_REGEX=^[^()][^()]*-([0123456789][0123456789][0123456789][0123456789])-.*\.pdf$" ^
& rem // (precise filter to exclude files violating the demanded pattern)
if not defined _REGEX set "_REGEX=.*" & rem // (avoid trouble with empty filter)
rem // Loop through all matching files:
for /F "eol=: tokens=1,2,* delims=()" %%F in ('
dir /B /A:-D "%_FILES%" ^| findstr /I /R /C:"%_REGEX%"
') do (
rem // Store the extracted file name parts:
set "LEFT=%%F" & set "YEAR=%%G" & set "REST=%%H"
setlocal EnableDelayedExpansion
rem // Reassemble the name and rename the file:
ECHO ren "!LEFT!(!YEAR!)!REST!" "(!YEAR!)-!LEFT!!REST:*-=!"
endlocal
)
endlocal
exit /B
After having verified the correct output, remove the upper-case ECHO command to actually rename files.
I am attempting to find multiple strings in files in a directory, there are thousands. I currently run the following command to search the directory:
findstr /s "customerid" *
Now this allows me to find the file that contains that string. I normally have two pieces of information a customer id and an event type. One customer can have up to 30 associated event such as "website registration".
What I would like to do is, search the directory for both the customer id and the event. Then copy the file to a new location. Is this possible in a batch file?
Supposing you want to find all files that contain both words (customer and event in this example), you could use the following script:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "PATTERN=*.txt"
set "SOURCE=."
set "TARGET=D:\Data"
set "STRING1=customer"
set "STRING2=event"
pushd "%SOURCE%" && (
for /F "delims=" %%F in ('findstr /S /M /I /R /C:"\<%STRING1%\>" "%PATTERN%"') do (
for /F "delims=" %%E in ('findstr /M /I /R /C:"\<%STRING2%\>" "%%F"') do (
ECHO copy "%%E" "%TARGET%\%%~nxE"
)
)
popd
)
endlocal
exit /B
After having tested the script, remove the upper-case ECHO in front of the copy command!
#echo off
setlocal enableextensions disabledelayedexpansion
set "sourceFolder=x:\somewhere"
set "targetFolder=y:\another\place"
set "customerID=00000000"
set "event=eeeeeeeeee"
for /f "delims=" %%a in ('
findstr /m /s /l /c:"%customerID%" "%sourceFolder%\*"
^| findstr /f:/ /m /l /c:"%event%"
') do (
ECHO copy "%%~fa" "%targetFolder%"
)
findstr can deal with it. We only need two instances
The first one will search all the input files for the first string, returning only the list of matching files. This list of files will be piped into the second instance
The second one will search the second string but only in the files found by the first instance, reading the list of files where to search from standard input stream (/f:/)
The rest of the code is just a for /f wrapping the two findstr commands to process the output of the second one and do the file copy.
After having tested the script, remove the upper-case ECHO in front of the copy command!
Basically I'm trying to write a batch file to insert some code into multiple files. Here are the details of what I'm tring to accomplish:
1. The input string comes from a file test.txt.
2. The string needs to be inserted as the second line of destination files.
3. Destination files are all the .xml files under the same direction as the batch file.
I suppose I should use a FOR loop to go through all .xml files. Something like
for /f %%i in ('dir /b *.xml') do ()
I've read though some tutorials and posts but can't find a way to add anything to files in a loop. Using Echo or TYPE doesn't seems to work for each file in a loop. How do I modify files in a loop?
Also to insert to a certain number of line some post say the file needs to be put into a variable. But my files are pretty large, which I don't want to put into variables. Is there another way to insert into a certain line in a file?
#ECHO OFF
SETLOCAL
FOR /f "delims=" %%i IN ('dir /b *.xml') DO (
SET line2=Y
(
FOR /f "usebackqdelims=" %%x IN ("%%i") DO (
ECHO(%%x
IF DEFINED line2 TYPE Line2.txt
SET "line2="
)
)>"%%~ni.lmx"
)
GOTO :EOF
This should work for you - but it will delete empty lines.
#echo off
set /P string=< test.txt
for %%a in (*.xml) do (
(for /F "usebackq tokens=1* delims=:" %%b in ('findstr /N "^" "%%a"') do (
if %%b equ 2 echo %string%
set "line=%%c"
setlocal EnableDelayedExpansion
echo(!line!
endlocal
)) > "%%a.new"
)
New files have .xml.new extension; you may add a couple lines to delete original .xml files and rename .xml.new ones to .xml.