Happy Friday Think-Tank!
I need some assistance with a Batch .BAT script. Specifically I need help with some "IF statement syntax"
I have a script that is renaming files. There are two files, one ending in four digits and the other ending in five digits. The files will be renamed with variables I have already pre-set earlier within my script.
So here is a scenario: We have two files in a directory located at
c:\Users\username\Desktop\test-dir
There are two files within test-dir:
file1.12345
file2.1234
A four digit ending is one variable type (VAR1), whereas a file ending in five digits is another variable type (VAR2).
I need an if statement to:
a) read all the files(s) with the chosen directory (without using a wildcard if possible).
b) determine based on the number of digits after the "." which variable to use.
c) once making that determination rename the file with the appropriate variables.
The final re-naming convention is as so: yyyymmddtype.1234/12345
So basically it would use the datestamp variable I already created, the type variable I already created to be injected by the if statement, and append with the original ending digits of the file.
I know this seems like a lot, but I am more so a bash script guy. I have all the elements in place, I just need the if statement and what feels like a for loop of some kind to tie it all together.
Any help would be great!
Thank you!
Sorry, not the option you where asking for. Instead of iterating over the full list checking each file for extension conformance, iterate over a list of patterns that will filter file list, renaming matching files with the asociated "type"
for %%v will iterate over variable list, for %%a will split the content of the variable in pattern and type, for %%f will generate the file list, filter with findstr using the retrieved pattern and rename matching files with the corresponding "type"
Rename command is preceded with a echo to output commands to console. If the output is correct, remove the echo to rename the files.
#echo off
rem Variables defined elsewhere
set "folder=c:\somewhere"
set "timestamp=yyyymmdd"
rem Rename pattern variables in the form pattern;type
set "var1=\.....$;type1"
set "var2=\......$;type2"
set "var1=\.[^.][^.][^.][^.]$;type1"
set "var2=\.[^.][^.][^.][^.][^.]$;type2"
setlocal enableextensions disabledelayedexpansion
for %%v in ("%var1%" "%var2%") do for /f "tokens=1,* delims=;" %%a in ("%%~v") do (
for /f "tokens=*" %%f in ('dir /a-d /b "%folder%" ^| findstr /r /c:"%%~a"') do (
echo ren "%folder%\%%~f" "%timestamp%%%~b%%~xf"
)
)
endlocal
#ECHO OFF &SETLOCAL
set "yyyymmdd=yyyymmdd"
set "VAR1=VAR1"
set "VAR2=VAR2"
for /f "delims=" %%a in ('dir /b /a-d^|findstr /re ".*\....."') do echo(ren "%%~a" "%yyyymmdd%%VAR1%%%~xa"
for /f "delims=" %%a in ('dir /b /a-d^|findstr /re ".*\......"') do echo(ren "%%~a" "%yyyymmdd%%VAR2%%%~xa"
remove echo( to get it working.
If I understand you then this will rename the two files using preset variables for each one:
for %%a in ("%userprofile%\Desktop\test-dir\*") do (
if "%%~xa"==".12345" ren "%%a" "%variableA%-%variableB%%%~xa"
) else (
ren "%%a" "%variableC%-%variableD%%%~xa"
)
)
Related
I have a batch that scans a folder and puts the files in folders depending of the first letter of each file :
setlocal EnableDelayedExpansion
::Fichiers non déplacés
set noms = gamelist.bmp test.gif truc.pdf
FOR /F "tokens=*" %%A in ('DIR /B /A:-D "%cd%\*"') do IF NOT "%%A"=="%~nx0" ( IF NOT "%%A" in %noms% (
set "FIRSTCHAR=%%~nA"
set "FIRSTCHAR=!FIRSTCHAR:~0,1!"
IF NOT EXIST "%cd%\!FIRSTCHAR!" MD "%cd%\!FIRSTCHAR!"
MOVE "%cd%\%%A" "%cd%\!FIRSTCHAR!"
))
I have two noob questions I gave all I have to make this script lol) :
I created an array named "noms" that I want to use to put filenames that won't be affected by the script (they won't be moved in the folder created by the script). Unfortunately, my "IF NOT "%%A" in %noms%" condition doesn't work. What is wrong please ?
Second question : do you think it's possible to put all the files that begin by a number in a unique folder, "0-9" for instance ?
Thanks for the help !
set "noms=gamelist.bmp test.gif truc.pdf"
FOR /F "tokens=*" %%A in ('DIR /B /A:-D "%cd%\*"') do (
set "mouvement=O"
for %%Q in ("%~nx0" %noms%) do if /i "%%~Q"=="%%~nxA" set "mouvement="
if defined mouvement (
Batch is sensitive to spaces in an ordinary string SET statement. SET FLAG = N sets a variable named "FLAGSpace" to a value of "SpaceN"
mouvement is initialised to a value (any value will do) for each filename, but if the filename matches any of the values in noms or the batch filename %~nx0 then it is set to nothing and becomes not defined.
I have a simple .bat script which renames all files in a folder using ren. The input argument is a path to a folder containing the files to be renamed. The script sometimes returns syntax errors which we've traced to the fact that sometimes the input path has forward slashes, backslashes, or a mix of both (and sometimes starts with a double forward slash). We would like to make this script more robust by allowing it to accept any of these types of paths, and cleaning up the path as part of the .bat script before calling the ren command.
So my question is: is there a (set of) command(s) I can apply to the file path argument (%1 in the example below) before calling the ren function that will correct all forward/backslashes to be consistent and avoid syntax errors? I don't have much experience with .bat scripts, so any code examples would be helpful.
#echo off
setlocal ENABLEDELAYEDEXPANSION
for %%F in (%1*.nc) do (
for /F "tokens=1-8 delims=_" %%a in ("%%~nF") do (
ren "%%F" "%%a_%%b_%%c_%%d_%%e_%%g_%%f_%%h.nc"
)
)
UPDATE: In the end, only the last suggestion by Magoo was needed, because changing %1 to "%~f1" fixed the slash issues. I also had to add %~f1\ to the first argument of the ren command because otherwise it was somehow looking in the wrong folder (the first for found the files ok, but the ren command was looking in the wrong folder.
#echo off
setlocal ENABLEDELAYEDEXPANSION
for /F "delims=" %%F in ('dir /b /a-d "%~f1\*.nc"') do (
for /F "tokens=1-8 delims=_" %%a in ("%%~nF") do (
ren "%~f1\%%~nF.nc" "%%a_%%b_%%c_%%d_%%e_%%g_%%f_%%h.nc"
)
)
set "corrected=%~1"
set "corrected=%corrected:/=\%"
Then use %corrected% in place of %1 AND quote the filename thus:
for %%F in ("%corrected%*.nc") do (
If %1 is always a directory-name, then add
if "%corrected:~-1%" neq "\" set "corrected=%corrected%\"
as a third set line before the for line.
The first set assigns the value of %1 to a variable corrected - the ~ removes any enclosing quotes.
The second set changes all strings matching that between the : and = into that between the = and % in the variable given and assigns to the first-mentioned variable (can be the same variable, as in this case)
The third set, if used, checks that the last character is \ and if it is not, appends a \.
The quoting of the filename-string allows there to be spaces in the path/filename and is harmless if there are no spaces.
To avoid attempting to rename a file twice, instead of
for %%F in ("%corrected%*.nc") do (
use
for /F "delims=" %%F in ('dir /b /a-d "%corrected%*.nc"') do (
This builds a list of filenames in memory, then processes that list.
So I am using an application that creates a series of .tif files with very annoying filenames that do not sort correctly in alphanumerical order. I have no way to change the behavior of this commercial software, so I must use my own creativity to rename the files so they may be processed externally in the correct order. For example, the files created look like this:
image.tif, image(2).tif, image(3).tif, ..., image(9).tif, image(10).tif, ..., image(n).tif
Where n is an integer not less than 2. The first file has no number in parenthesis. Sorted alphanumerically, for example, the list would look like:
image.tif, image(10).tif, image(100).tif, image(1000), image(2).tif, ...
Obviously while this is the correct alphanumerical order, it's the incorrect numerical order. So with the aid of some batch commands, I created this:
#echo off & setlocal EnableDelayedExpansion
ren "image.tif" "a.tif"
ren "image(1).tif" "b.tif"
ren "image(2).tif" "c.tif"
ren "image(3).tif" "d.tif"
ren "image(4).tif" "e.tif"
ren "image(5).tif" "f.tif"
ren "image(6).tif" "g.tif"
ren "image(7).tif" "h.tif"
ren "image(8).tif" "i.tif"
ren "image(9).tif" "j.tif"
set a=1
for /f "delims=" %%i in ('dir /b *.tif') do (
ren "%%i" "!a!.tif"
set /a a+=1
)
This at least corrects the names of the first ten files, as I often process less than 100 files. The for loop is a snippet I found here on stackoverflow, it renames the alphanumeric files into integers starting with 1 up to the number of files.
Problem I run into is that this loop still creates 1.tif, 10.tif, and 100.tif that would come before 2.tif.
I've seen the use of %02d to format numbers into 01, 02, 10, etc. Does anyone know how to syntactically include that in the loop shown above?
Or if anyone can figure a more elegant method to rename these files into a suitable alphanumeric order, it would be greatly appreciated. I have the feeling my solution is very kludgey.
#echo off
setlocal EnableDelayedExpansion
rem Initialize "i" variable with the desired number of digits as zeros
set i=1000
rem Process the files in creation date-time order
for /F "delims=" %%a in ('dir /A-D /OD /B *.tif') do (
rem Increment the number: "1001"...
set /A i+=1
rem Omit first digit in number: "1", use the rest: "001"...
ren "%%a" "image(!i:~1!).tif"
)
#echo off
setlocal EnableDelayedExpansion
set /a max=99&set /a numlen=2
if exist "image(100).tif" set /a max=999&set /a numlen=3
for /L %%a in (1,1,%max%) do if exist "image(%%a).tif" set /a newnum=1000+%%a&if not exist "image(!newnum:~-%numlen%!).tif" echo(ren "image(%%a).tif" "image(!newnum:~-%numlen%!).tif"
set /a max+=1
echo(ren "image.tif" "image(!newnum:~-%numlen%!).tif"
[untested]
If "image(100).tif" exists, then we need to rename to (001)..(999). If not, to (01)..(99), so then number-length will be 3 or 2.
for each of the names 1..max, if the file exists, calculate 1000+the file number;take the last 3 or 2 characters and rename. Only attempt to rename if the destination name does not exist, so (6) will be renamed to (006) or (06), (15) to (05) or skipped as (15)=(15) and (123) will also be skipped as (123)=(123)
Finally, rename the image.tif file to (000) or (00)
Note that this will simply echo the required commands to allow verification. Change the echo(ren to ren when verified to actually perform the rename.
The %02d convention for padding numbers is a printf thing, not really applicable to the Windows cmd environment or batch scripting. PowerShell has something similar, but not pure batch. However, you can zero-pad numerals pretty easily using variable substring manipulation.
set /a a=0
for /f "delims=" %%I in ('dir /b *.tif') do (
set "idx=00!a!"
ren "%%~I" "!idx:~-3!%%~xI"
set /a a += 1
)
If you'd prefer to keep the naming convention of image(idx).tif while ensuring the TIF files remain in their intended sequential order, a lazy solution might be to use prename.bat and rename with regexps.
prename /v "s/\((\d)\)/(00\1)/" *.tif
prename /v "s/\((\d\d)\)/(0\1)/" *.tif
In cmd there are no format strings like %02d. However, you can use dir /B to retrieve a plain list of files, findstr to filter for those having a parenthesised numeric suffix in their names or no such suffix at all, for /F to capture the resulting file names and split them into tokens relying on (, ), and sub-string expansion to do the actual left-zero-padding, like in the following example:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_LOCATION=." & rem // (directory containing the files to rename)
set "_PATTERN=*.tif" & rem // (search pattern for the files to rename)
set /A "_DIGITS=4" & rem // (number of proposed digits from 1 to 10)
set "_REGEX1=^[^()][^()]*([0-9][0-9]*)\.tif$" & rem // (filter expression)
set "_REGEX2=^[^()][^()]*\.tif$" & rem // (filter expression)
rem // (the filter expressions ensure wrongly named files not to be processed)
rem // Build zero-padding string:
set "PAD=0000000000" & call set "PAD=%%PAD:~-%_DIGITS%%%"
rem // Loop through all matching files:
for /F "tokens=1-3 delims=()" %%A in ('
dir /B /O:N "%_PATTERN%" ^| findstr /I /R /C:"%_REGEX1%" /C:"%_REGEX2%"
') do (
rem // Check if current file name contains a parenthesised numeric suffix:
if not "%%B"=="" (
rem // Numeric suffix found, so store file name parts and pad number:
set "LEFT=%%A" & set "MID=%PAD%%%B" & set "RIGHT=%%C"
setlocal EnableDelayedExpansion
ECHO rename "!LEFT!(%%B)!RIGHT!" "!LEFT!(!MID:~-%_DIGITS%!)!RIGHT!"
endlocal
) else (
rem // No numeric suffix encountered, so append zero-suffix:
ECHO rename "%%A" "%%~nA(%PAD%)%%~xA"
)
)
endlocal
exit /B
After having successfully verified the appropriate output of the script, remove the upper-case ECHO command to actually rename any files.
The script renames a file like image.tif to image(0000).tif (supposing there is no file named image(0).tif, originally). If you do not want that to happen, simply remove the /C:"%_REGEX2%" part from the findstr command line.
I am looking to batch rename a large number of files by adding a suffix of an alpha character, but only in a specific range. For example: File 126.pdf should be renamed 126A.pdf, File 127.pdf should be renamed 127B.pdf, File 128.pdf should be renamed 128A.pdf, File 129.pdf should be renamed 129B.pdf, etc. Any existing software that is capable of doing this is also appreciated.
Thanks!
setlocal EnableDelayedExpansion
rem Define the set of replacements
for %%a in ("126=126A" "127=127B" "128=128A" "129=129B") do set %%~a
rem Achieve the replacements
for %%a in (*.pdf) do (
if defined %%~Na (
ren "%%a" "!%%~Na!.pdf"
)
)
Previous program is based on the examples given in your request. Perhaps if you define the rename rules in a different, more precise way, the program may be entirely different!
You could try the following:
#ECHO OFF
SETLOCAL EnableDelayedExpansion
SET suffixes=AB
FOR %%I IN (*.pdf) DO (
RENAME "%%I" "%%~nI!suffixes:~0,1!.*"
SET suffixes=!suffixes:~1!!suffixes:~0,1!
)
The suffixes variable is set to an "array" of all the possible suffixes to use with renaming.
When iterating over the files, the first suffix in the array is picked to form a new name. Then the suffixes are swapped in the array, so the other one becomes first at the next iteration.
This solution will work with an arbitrary number of suffixes.
You could use a FOR loop to examine each single filename.
setlocal EnableDelayedExpansion
for %%A in (*.pdf) DO (
echo Filename=%%A
set name=%%~nA
set "prefix="
if !name! == 123 set prefix=A
if !name! == 999 set prefix=B
echo rename "%%A" to "!name!!prefix!.pdf"
ren "%%A" "!name!!prefix!.pdf"
)
The code below works fine, here is a list of it's functions:
It moves files based on the fist 4 characters to a pre-created folder with the same first 4 characters
If the folder does not exist, it will not move the file, as there is no folder with the same fist 4 chars.
#echo on
setlocal enabledelayedexpansion
cls
pushd R:\Contracts\Sites
for /f "tokens=*" %%1 in ('dir /a-d /b *') do (
set filename=%%1&set dirname=!filename:~0,4!
for /f "tokens=*" %%A in ('dir /ad /b') do (
set dirid=%%A & set dirid=!dirid:~0,4!
if "!dirid!" equ "!dirname!" move %%1 %%A
)
)
I would like to add one extra function to this code please. Pleas have a look at the example below.
I have 5 files
X32A-test.docx or X32A-test.pptx (there will only be one docx or pptx, "NEVER two with the same name")
X32A-test.pdf
X32A-test.avi
X32A-test-eng.sub
X32A-test-small.jpg
I would like the code to CREATE a folder if it does not exist, based on the file name if it has the extension docx or pptx.
So with the above example it would create a folder named: "X32A-test". Then all the other files with "X32A" in the front of the name will be moved to that newly created folder "X32A-test".
I hope it is clear enough. If not please ask me for more information.
Thank you
It is much simpler and more efficient to use the simple FOR instead of FOR /F in your case.
And rather than looping through every file and moving them individually, it is easier and more efficient to use wildcards.
The first loop finds the .pptx and .docx files and creates folders as needed
The second loop finds all the directories and moves all files that start with the directory name into the directory.
#echo on
setlocal enableDelayedExpansion
cls
pushd R:\Contracts\Sites
for %%F in (*.docx *.pptx) do (
set "folder=%%F"
2>nul md !folder:~0,4!
)
for /d %%F in (*) do move %%F* %%F
popd
If needed, you can protect yourself against directory names shorter than length 4.
#echo on
setlocal enableDelayedExpansion
cls
pushd R:\Contracts\Sites
for %%F in (*.docx *.pptx) do (
set "folder=%%F"
set folder=!folder:~0,4!
if !folder:~0,3! neq !folder! 2>nul md !folder!
)
for /d %%F in (????) do (
set "folder=%%F"
if "!folder:~0,3!" neq "%%F" move %%F* %%F
)
popd
Note that this solution may fail if a file name contains !. If that arises then you need to toggle delayed expansion on and off within the loop(s).
I can see the entire process (including the part already implemented) like this:
All the files that are not yet in their "home" directories are moved there.
For all .docx and .pptx files left, create directories based on the files' names.
Obviously, the step #2 creates new "homes" and those will still be "uninhabited" this far. So all that is left to do now is to repeat the step #1.
So I would probably reorganised your process and, with the additional requirement, it could be implemented this way:
…
PUSHD your_root_directory
FOR /D %%D IN (*) DO (
CALL :movefiles "%%D"
)
FOR %%F in (*.docx *.pptx) DO (
MKDIR "%%~dpnF"
CALL :movefiles "%%~dpnF"
)
…
GOTO :EOF
:movefiles
SET "dirname=%~n1"
SET "mask=%dirname:~0,4%*"
MOVE "%~dp1%mask%" %1
Note: The steps #2 and #3 could be either implemented as separate loops or combined in one. The above script uses the latter approach.
You can use negative offsets in the !var:~offset,len! evaluation as follows:
set fspec=X32A-test.docx
echo !fspec:~-10!
echo !fspec:~0,-10!
That second line above gives you -test.docx and you can simply check that against your two desired possibilities with an if statement (or two).
Then you can use the third line to get the rest of the name for creating a directory.
The following example script shows how this could be done:
#setlocal enableextensions enabledelayedexpansion
#echo off
set fspec=X32A-test.docx
set bit1=!fspec:~-10!
set bit2=!fspec:~0,-10!
if .!bit1!.==.-test.docx. echo mkdir !bit2!
if .!bit1!.==.-test.pptx. echo mkdir !bit2!
endlocal
I'm echoing the mkdir command rather than executing it so you need to take out the echo. You'll also need to integrate the set and if statements into your loop but, based on what you have so far, you should have little trouble with that.
If, as you seem to indicate in a comment, the first four characters are the key and the last five decide on whether to make the directory, as in:
x32s-test.docx
a21w-production.pptx
xxxx-whatever_the_blazes_you_want.some_other_rubbish.docx
Then you're really only interested in the first four and last five:
#setlocal enableextensions enabledelayedexpansion
#echo off
set fspec=a12b-whatever_the_blazes_you_want.some_other_rubbish.docx
set bit1=!fspec:~-5!
set bit2=!fspec:~0,4!
if .!bit1!.==..docx. echo mkdir !bit2!
if .!bit1!.==..pptx. echo mkdir !bit2!
endlocal
This checks the correct extensions and outputs:
mkdir a12b
as expected.