I have a folder with 460 images with 23 per person in the format: image_0001.jpg to image_0460.jpg.
What is the batch command to rename them in the form 01-01.jpg to 01-23.jpg for a person and thus the entire database upto 20-23.jpg?
[EDIT]
I came across:
#echo off & setlocal EnableDelayedExpansion
set a=1
for /f "delims=" %%i in ('dir /b *') do (
if not "%%~nxi"=="%~nx0" (
ren "%%i" "!a!"
set /a a+=1
)
)
I could not find a way to use loop variables to do the same. Is there a way to use loop variables or is there another way?
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir"
SET /a filenum=10000
FOR /L %%a IN (1,1,20) DO (
FOR /L %%b IN (1,1,23) DO (
SET /a filenum+=1
SET /a newnum=10000+%%b+(%%a*100^)
ECHO(REN "%sourcedir%\image_!filenum:~-4!.jpg" "!newnum:~1,2!-!newnum:~-2!".jpg
)
)
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.
The issue is one of leading zeroes, hence invoke delayedexpansion and calculate using 10000+a significant number, then substring.
The rest is simply a matter of mathematics.
This method use the % (modulus or remainder) operator to count in groups of 23: the image=(image+1)%23 part vary image variable from 0 to 22 and repeat this count. imgaux=101+image vary imgaux from 101 to 123 and just the last two digits are used in the ren command. Finally, person+=!image increment person variable each time that image is zero.
#echo off
setlocal EnableDelayedExpansion
set /A person=100, image=-1
for %%a in (*.jpg) do (
set /A "image=(image+1)%%23, imgaux=101+image, person+=^!image"
ECHO ren "%%a" "!person:~1!-!imgaux:~1!.jpg"
)
Note that in this method the number of persons doesn't need to be known in advance.
Related
I have a text file (Myfile.txt), line by line, which is very long and centered as shown below
...","ItemPrice":17000.0,"MustPay":17000.0,"PaywithCash":17000.0,"etc...
...","ItemPrice":900.0,"MustPay":900.0,"PaywithCash":900.0,"etc...
...","ItemPrice":1400.0,"MustPay":1400.0,"PaywithCash":1400.0,"etc...
so I want to get the number after the word "PayWithCash":, for example the first line is the number 17000 and so on to the next line, and save it to a new text file "result.txt"
1700
900
1400
I have tried several codes, including as below
echo off
SETLOCAL EnableDelayedExpansion
for /f "delims=" %%a in ('type Myfile.txt^|find "PayWithCash:"') do (
set "line=%%a"
set "line=!line:*PayWithCash =!
set /a "last=!line:~1!" 2>nul
)
echo %last% >> result.txt
And yes, I still can't get the desired result, can you help me?
I use google translate, I hope you understand
Correct PayWithCash to the correct case in the data, PaywithCash or add the /i switch to find to make the match case-insensitive.
Remove the colon as suggested by #Compo.
Remove the Space after PayWithCash in the set statement as there is no such Space in the data.
Since the result in line will now begin ": you need to use line:~2
Test code I used:
#ECHO OFF
SETLOCAL EnableDelayedExpansion
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
SET "filename1=%sourcedir%\q64838297.txt"
SET "outfile=%destdir%\outfile.txt"
(
for /f "delims=" %%a in ('type "%filename1%"^|find /i "PayWithCash"') do (
set "line=%%a"
set "line=!line:*PayWithCash=!"
set /a "last=!line:~2!" 2>nul
echo !last!
)
)>"%outfile%"
TYPE "%outfile%"
GOTO :EOF
You would need to change the settings of sourcedir and destdir to suit your circumstances. The listing uses a setting that suits my system.
I used a file named q64838297.txt containing your data for my testing.
Produces the file defined as %outfile%
Result:
17000
900
1400
So in Windows Explorer, I have these files sorted like this:
I have this script to remove the brackets and one zero, and in case the trailing number is greater than or equal to 10, to remove two zeroes:
cd C:\folder
setlocal enabledelayedexpansion
SET /A COUNT=0
for %%a in (*.jpg) do (
SET /A COUNT+=1
ECHO !COUNT!
set f=%%a
IF !COUNT! GTR 9 (
set f=!f:^00 (=!
) ELSE (
set f=!f:^0 (=!
)
set f=!f:^)=!
ren "%%a" "!f!"
)
pause
However, once I run the code, I get this result:
So the batch file isn't going through the files "intuitively" like Windows Explorer shows them. Is there any way to change this? Or is there a better way to rename these files altogether?
This uses a different approach:
#echo off
cd C:\folder
setlocal enabledelayedexpansion
SET /A COUNT=0, REMOVE=2
for /F "delims=(" %%a in ('dir /B *.jpg') do (
SET /A COUNT+=1
ECHO !COUNT!
set "f=%%a"
IF !COUNT! EQU 10 SET "REMOVE=3"
for /F %%r in ("!REMOVE!") do set "f=!f:~0,-%%r!"
ren "%%a" "!f!!COUNT!.jpg"
)
pause
Here is a method that does not depend on the sort order used by the file system, preserving the numbers as occurring in the original file names.
For each file name (for instance, test_this_01 SELR_Opening_00000 (1).jpg), the portion after the last under-score _ is retrieved (00000 (1)). Then the parentheses and the space are removed and then the length is trimmed to five characters (00001). This string replaces the original one in the file name finally (test_this_01 SELR_Opening_00001.jpg); the file name must not contain the replaced portion (00000 (1)) multiple times (hence file names like this should not occur: test_this_00000 (1) SELR_Opening_00000 (1).jpg):
#echo off
setlocal DisableDelayedExpansion
rem // Define constants here:
set "LOCATION=."
set "PATTERN=*_* (*).jpg"
set /A "DIGITS=5"
pushd "%LOCATION%" || exit /B 1
for /F "usebackq eol=| delims=" %%F in (`
dir /B /A:-D /O:D /T:C "%PATTERN%"
`) do (
set "FILE=%%F"
setlocal EnableDelayedExpansion
set "LAST="
for %%I in ("!FILE:_=","!") do (
set "LAST=%%~nI" & set "FEXT=%%~xI"
set "FNEW=!FILE:%%~I=!"
)
set "LAST=!LAST:(=!" & set "LAST=!LAST:)=!"
set "LAST=!LAST: =!" & set "LAST=!LAST:~-5!"
ECHO ren "!FILE!" "!FNEW!!LAST!!FEXT!"
endlocal
)
popd
endlocal
exit /B
Adapt the directory location and the file search pattern in the top section of the script as you like.
After having tested, remove the upper-case ECHO command in order to actually rename files.
I'm really close, I think. I'm not great at this kind of stuff, but I've cobbled together code I found searching here. Maybe you can figure out what I'm doing wrong. Here's what I've got:
#echo off
setlocal enableextensions disabledelayedexpansion
set /p "number=Please enter the starting control number:" || goto :eof
for /f "delims=" %%a in (List.txt) do (
setlocal enabledelayedexpansion
for %%b in (!number!) do (
endlocal
echo copy "%%~fa" "c:\myfolder\%%b_%%~nx"
)
set /a "number+=1"
)
So far it outputs as needed, except the file isn't created with theoriginal name at the end. It actually suffixes "%~nx" as text.
Essentially, I want it to take the original file, tack on a prefix, counting up from a provided number, padded (this part I haven't worked on yet), into a new folder.
Thanks for reading!
Here's what I neded up with:
setlocal enableextensions enabledelayedexpansion
set /p "dir=Set output dir:" || goto :eof
set /p "d=Set total digits:" || goto :eof
set number=1
for /f "delims=" %%a in (List.txt) do (
setlocal enabledelayedexpansion
for %%b in (!number!) do (
set "pad=0000000000%%b"
set "name=!pad:~-%d%!
copy "%%~fa" "%dir%\!name!_%%~nxa"
)
set /a "number+=1"
)
~nx is the name of a variable called x. Perhaps you meant either ~nxa or ~nxb which is name and extension of your two for variables.
Why is there an EndLocal in the middle of a loop?
I'm attempting to use a batch file to keep all files in a particular folder numbered sequentially (0,1,2,...). To do this I first require knowing what the highest number in this sequence is so I can append the non-sequentially named files to the end of the list. For example, I may have the following files:
0.png
1.jpg
2.jpg
3.png
file_51.jpg
pictureabc.png
This would return a result of 3 as that is the last filename in sequence. I would then be able to find the remaining files (not sure the best way to do this either) and number them starting at 4.
The only solution I have come up with so far is using an infinite goto loop that stops when no filename including that number exists.
set count=0
:loop
if exist %count%.* set /a count+=1 & goto loop
This solution is highly inefficient however and takes almost a minute for 100 thousand images. I'm looking for a solution that will be able to achieve this in under 10 seconds if possible.
#echo off
setlocal enableextensions disabledelayedexpansion
setlocal enabledelayedexpansion
set "nextFile=0" & for /f "delims=" %%a in ('
dir /a-d /b ^| findstr /b /r /x
/c:"[1-9][0-9]*\.[^.]*"
/c:"[1-9][0-9]*"
/c:"0"
') do if %%~na geq !nextFile! set /a "nextFile=%%~na+1"
endlocal & set "nextFile=%nextFile%"
echo Next file will be: %nextFile%
This just uses a dir command to retrieve the list of all files, filtered with findstr to only get those with numeric name. The rest is just compare the file name against the previous max value.
Edited - This should work fast enough
#if (#This === #IsBatch)
#echo off
rem Start of batch zone ----------------------------------------------
setlocal enableextensions disabledelayedexpansion
for /f %%a in ('
dir /a-d /b /o-d
^| findstr /r /x /c:"[0-9][0-9]*\.[^.]*" /c:"[0-9][0-9]*"
^| cscript //nologo //e:jscript "%~f0"
') do set "nextFile=%%a"
echo next file will be %nextFile%
exit /b
#end
// Start of JScript zone ---------------------------------------------
var inputStream = WScript.StdIn;
var max = 0, value ;
while(!WScript.StdIn.AtEndOfStream) {
value = parseInt( inputStream.ReadLine().split('.')[0], 10 );
if ( value >= max ) max = value + 1;
}
WScript.StdOut.WriteLine( max );
This is an hybrid batch/jscript file. Saved as .cmd file, it uses a dir command to retrieve the list of files, a findstr to leave only the files with numbered names and then the native JScript engine to extract the numbers and search for the greatest value.
I think this is the fastest way:
#echo off
setlocal EnableDelayedExpansion
set lastNum=0
for /L %%a in (1,1,9) do (
for %%b in (%%a*.*) do (
if %%~Nb gtr !lastNum! (
set lastNum=%%~Nb
)
)
)
echo Last numbered file: %lastNum%
EDIT: New method added
Previous method depends on the number of existent files, so it is not as fast as I expected...
The new method below takes almost the same time no matter the number of files:
#echo off
setlocal EnableDelayedExpansion
set "names="
for /L %%i in (1,1,9) do set "names=!names! %%i*.*"
dir /B /A-D /O-D %names% 2> NUL | ( set /P "lastNum=" & set lastNum ) > lastNum.txt
for /F "tokens=2 delims==." %%a in (lastNum.txt) do set "lastNum=%%a"
del lastNum.txt
echo Last numbered file: %lastNum%
Previous method may fail if more than one of the last files have the same created time, but this point may be fixed if needed.
sorry - but the last method by Aacini works really bad. Actually it does not find the highest number, but the file created (not modified) last. It would be great to know how to fix this!
Stopping at hole can be fixed with iterations (yeah 2 lines of code for each subsequent hole).
here is how to iterate...
set count=1234 ::starting number
:loop
if exist %count%.img set /a count+=1 & goto loop
set /a count+=1
if exist %count%.img set /a count+=1 & goto loop
set /a count+=1
if exist %count%.img set /a count+=1 & goto loop
set /a count=%count%-2
need to reduce the count at the end again. This could be made much longer of course but then it will slow down if you iterate 1000 times...
I have a directory with many sub-directories that contain thousands of jpgs. What I want to do is create a batch script that will go through all of the sub-directories and delete every 2nd image i.e. keep the first, third, fifth image but delete the second, fourth, and six image etc per directory (ordered by filename).
I tried with the following but my knowledge of batch scripting is poor, and the syntax is clearly incorrect.
#echo off
set z = 0
for /f %%a in ('dir/b *.jpg')
do (
set z = z + 1
if z == 2 del %%a
)
The DO must be on the same line as FOR.
You must use SET /A if you want to do math
Your logic is wrong - Currently it will only delete the 2nd file, not every other one. You should take the mod 2 value (remainder devided by 2) and delete if the result is 0.
You must use %z% if you want to see the current value (except within a SET /A statement). But that will not work inside a code block that just set the value. In that case you need to enable delayed expansion and use !z! instead.
Expanding a FOR variable that contains ! (valid in file names) while delayed expansion is enabled will corrupt the value. So delayed expansion must be toggled on and off
You say you want to recurse sub-directories, but your code only looks at one folder.
Spaces are significant in the SET statement. Your code defines a variable z with a space at the end of the name. Not what you want.
Here is a debugged version:
#echo off
setlocal
for /r %%D in (.) do (
set "z=0"
for /f %%F in ('dir /b "%%D\*.jpg"') do (
set /a "z+=1, r=z%%2"
setlocal enableDelayedExpansion
if !r! equ 0 del "%%D\%%F"
endlocal
)
)
There are ways to solve this without delayed expansion. One is to simply alternate between defining and undefining a variable.
#echo off
setlocal
for /r %%D in (.) do (
set "del="
for /f %%F in ('dir /b "%%D\*.jpg"') do if defined del (
del "%%D\%%F"
set "del="
) else set "del=1"
)
Another is to intentionally divide by 0 when you want to delete, and delete only when there is an error. Error messages are hidden by 2>nul, and the || operator conditionally executes the following command only if the prior command failed.
#echo off
setlocal
for /r %%D in (.) do (
set "z=0"
for /f %%F in ('dir /b "%%D\*.jpg"') do 2>nul set /a "z+=1, 1/(z%%2)" || del "%%D\%%F"
)
try this and remove the echo if the output looks good:
#echo off &setlocal
for /f "tokens=1*delims=:" %%a in ('dir /b /s /a-d *.jpg^|findstr /n $') do (
echo %%a|findstr "[02468]$" >nul && echo del "%%~b"
)