rename all files sequentially with same extension using batch file - windows

I wanna rename this files like that:
File 1.pdf > 1.pdf
File 2.pdf > 2.pdf
..
File 10.pdf >10.pdf
File 11.pdf >11.pdf
File1 1.pdf >12.pdf
File1 2.pdf >13.pdf
..
This code it's working but not Sorting Them:
#echo off & setlocal EnableDelayedExpansion
set a=1
for /f "delims=" %%i in ('dir /b *.pdf') do (
ren "%%i" "!a!.pdf"
set /a a+=1
)
The result is :
File 1.pdf > 1.pdf
File 10.pdf > 2.pdf
File 11.pdf > 3.pdf

#echo off
setlocal enabledelayedexpansion
if "%~1" == "stage1" goto :stage1
if "%~1" == "stage2" goto :stage2
if not "%~1" == "" exit /b 1
cmd /c "%~f0" stage1 | sort | cmd /c "%~f0" stage2
exit /b 0
:stage1
for /f "delims=" %%A in ('dir /b *.pdf') do (
for /f "tokens=1,*" %%B in ("%%~nA") do (
set "token1=%%~B "
set "token2= %%~C"
echo "!token1:~0,20!"^|"!token2:~-20!"^|"%%~A"
)
)
exit /b 0
:stage2
set i=0
for /f "delims=" %%A in ('more') do (
set /a "i+=1"
for /f "tokens=3 delims=|" %%B in ("%%~A") do (
echo ren "%%~B" "!i!.pdf"
)
)
exit /b 0
Label stage1 pads the 2 tokens of the filename with spaces and then trims each to 20 characters in length. Each line is echoed with "token1 padded"|"token2 padded"|"full filename", which is piped to sort, and then piped to label stage2 for indexing and renaming.
Remove the echo in front of the ren command if test is good.
Output:
ren "File 1.pdf" "1.pdf"
ren "File 2.pdf" "2.pdf"
ren "File 10.pdf" "3.pdf"
ren "File 11.pdf" "4.pdf"
ren "File1 1.pdf" "5.pdf"
ren "File1 2.pdf" "6.pdf"

You can test a to see if it is less than 10 and add a zero to the filename like this:
if !a! LSS 10 ren "%%i" "0!a!.pdf" else ren "%%i" "!a!.pdf"
If you have more than 100 file to rename, you can make it like this:
if !a! LSS 10 set newfile="00!a!" else if !a! LSS 100 set newfile="0!a!"
ren "%%i" "!newfile!.pdf"
Putting it all together, this worked for me:
#echo off & setlocal EnableDelayedExpansion
set a=1
for /f "delims=" %%i in ('dir /b *.pdf') do (
set newfile="!a!"
if !a! LSS 1000 set newfile="0!a!"
if !a! LSS 100 set newfile="00!a!"
if !a! LSS 10 set newfile="000!a!"
ren "%%i" "!newfile!.pdf"
set /a a+=1
)

Related

Looping through %1 as a directory in batch?

I've searched the web for answers but can't seem to find an answer. I want the user to provide a directory and to be able to loop through it. I'm able to loop through the current directory like so:
#Echo off
for /r %%f in (*.*) do (
echo %%f
)
But then when I try to do the same by looping through %1, I can't get the result I'm looking for. What am I doing wrong? Here's where I'm at in the batch file:
#Echo off
if exist %1 (
for /r %%f in (%1) do (
echo %%f
)
) else (
echo "That directory does not exist."
)
I've tried using /D but all that did was echo the directory I provided like this:
FileCount C:\Users\Me\Desktop
> C:\Users\Me\Desktop
Edit: My goal for this program is to eventually count the number of files within the given directory. I expect the directory to be provided as it's absolute path and I'll be executing this file through cmd. Here's an example of the input I'm expecting.
FileCount C:\Users\Me\Desktop
And the desired output would be something like:
> Hello world.txt
> Cat.png
> There are 2 files within this directory.
Side-note: I don't want to filter out the output of the dir command, I want to do this with a for loop.
Here's what you asked for, plus the optional recurs feature. Note that this will miss hidden files and directories.
#setlocal EnableExtensions
#prompt=$G
#set _Error_Success=0
#set _Error_PathNotFound=3
#if "%~1" equ "/?" goto :Usage
#if "%~1" equ "" goto :Usage
#if "%~1" equ "/r" (#set _recurs=/r & #set _root=%~2) else (#set _root=%~1)
#if not exist "%_root%" goto :Oops
#set count=0
#pushd "%_root%"
#for %_recurs% %%f in (*) do #call :Counter "%%f"
#popd
#echo There are %count% entries within this directory.
#exit /b %_Error_Success%
:Counter
#set /a count+=1
#echo %~1
#exit /b %_Error_Success%
:Oops
#echo "That directory does not exist."
#exit /b %_Error_PathNotFound%
:Usage
#echo Usage: FileCount [/r] path
And this uses the dir command, without resorting to invoking findstr:
#setlocal EnableExtensions
#prompt=$G
#set _Error_Success=0
#set _Error_PathNotFound=3
#set _Error_InvalidParameter=87
#set _attributes=
#set _recurs=
#set _count=0
#if "%~1" equ "/?" #goto :Usage & #exit
#if "%~1" equ "" goto :Usage
#set _root=%~1
#if not exist "%_root%" goto :Oops
#shift
#pushd "%_root%"
for /f %%G in ('dir /B /A-d %1 %2 %_root%') do #call :Counter "%%G"
#popd
#echo There are %_count% entries within this directory.
#exit /b %_Error_Success%
:Counter
#set /a _count+=1
#echo %~1
#exit /b %_Error_Success%
:HandleOptions
:Oops
#echo "That directory does not exist."
#exit /b %_Error_PathNotFound%
:Usage
#echo Usage: FileCount [/A<Attributes>] [/S] rootPath
#echo Where <Attributes> corresponds to 'dir /A' optiions (see 'help dir')
#echo and /S will cause recursion into subdirectories of rootPath.
This example, uses a for loop, and does not use the dir command, as per your inexplicable request, but it does use xcopy to list and count the files within it instead:
#For %%G In ("%~1") Do #If "%%~aG" Lss "d" (If "%%~aG" GEq "-" (
Echo Error: File argument given, expected a directory.
%SystemRoot%\System32\timeout.exe /T 3 /NoBreak 1> NUL
Exit /B 1) Else (
Echo Error: Invalid argument, directory path expected.
%SystemRoot%\System32\timeout.exe /T 3 /NoBreak 1> NUL
Exit /B 1)
) Else Echo File content of "%~1":& For /F Delims^= %%H In (
'%SystemRoot%\System32\xcopy.exe "%~1" : /HIL') Do #Echo %%~nxH
#%SystemRoot%\System32\timeout.exe /T -1 & Exit /B 0
If you want it to recurse the input directory, then I'd suggest this very small modification:
#For %%G In ("%~1") Do #If "%%~aG" Lss "d" (If "%%~aG" GEq "-" (
Echo Error: File argument given, expected a directory.
%SystemRoot%\System32\timeout.exe /T 3 /NoBreak 1> NUL
Exit /B 1) Else (
Echo Error: Invalid argument, directory path expected.
%SystemRoot%\System32\timeout.exe /T 3 /NoBreak 1> NUL
Exit /B 1)
) Else Echo File content of "%~1":& For /F Delims^= %%H In (
'%SystemRoot%\System32\xcopy.exe "%~1" : /HILS') Do #Echo %%H
#%SystemRoot%\System32\timeout.exe /T -1 & Exit /B 0
Or with a little more work, outputting relative paths instead:
#For %%G In ("%~1") Do #If "%%~aG" Lss "d" (If "%%~aG" GEq "-" (
Echo Error: File argument given, expected a directory.
%SystemRoot%\System32\timeout.exe /T 3 /NoBreak 1> NUL
Exit /B 1) Else (
Echo Error: Invalid argument, directory path expected.
%SystemRoot%\System32\timeout.exe /T 3 /NoBreak 1> NUL
Exit /B 1)
) Else Echo File content of "%~1":& For /F Delims^= %%H In (
'%SystemRoot%\System32\xcopy.exe "%~1" : /HILS') Do #(
Set "}=%%H" & SetLocal EnableDelayedExpansion
For %%I In ("!}:*%~1=.!") Do #EndLocal & Echo %%~I)
#%SystemRoot%\System32\timeout.exe /T -1 & Exit /B 0
setlocal enabledelayedexpansion
rem Put it into a folder that is in ENV PATH variable.
rem So, you can call it from wherever you want.
if not "%~1"=="" (
if exist "%~dpn1" (
set /a "filecount=0"
for /f "tokens=* delims=" %%f in ('dir /b "%~dpn1"') do (
echo %%f
set /a "filecount+=1"
)
echo:
echo In "%~dpn1" found !filecount! file^(s^).
) else (
echo:
echo [ERROR] Invalid input. Please specify:
echo 1. A full path.
echo 2. A folder in cwd.
echo:
echo If input is empty, current working directory (cwd)
echo will be considered.
exit /b 1
)
) else (
set /a "filecount=0"
for /f "tokens=* delims=" %%f in ('dir /b "%~dp0"') do (
echo %%f
set /a "filecount+=1"
)
echo:
echo In "%~dp0" found !filecount! file^(s^).
)
endlocal
If you want it recursive call it as progname.bat /r [foldname]:
setlocal enabledelayedexpansion
rem Put it into a folder that is in ENV PATH variable.
rem So, you can call it from wherever you want.
if "%1"=="/r" shift
if not "%1"=="" (
if exist "%~dpn1" (
set /a "filecount=0"
set /a "totalcount=0"
set "oldroot=%~dpn1"
for /f "tokens=* delims=" %%f in ('dir /b /s "!cd!"') do (
if not "%%~dpf"=="!oldroot!" (
echo:
echo In "!oldroot!" found !filecount! file^(s^).
echo:
set /a "filecount=0"
set "oldroot=%%~dpf"
)
echo --- %%f
set /a "filecount+=1"
set /a "totalcount+=1"
)
echo:
echo In "%~dpn1" found !totalcount! file^(s^).
) else (
echo:
echo [ERROR] Invalid input. Please specify:
echo 1. A full path.
echo 2. A folder in cwd.
echo:
echo If input is empty, current working directory (cwd)
echo will be considered.
exit /b 1
)
) else (
set /a "filecount=0"
set /a "totalcount=0"
set "oldroot=!cd!"
for /f "tokens=* delims=" %%f in ('dir /b /s "!cd!"') do (
if not "%%~dpf"=="!oldroot!" (
echo:
echo In "!oldroot!" found !filecount! file^(s^).
echo:
set /a "filecount=0"
set "oldroot=%%~dpf"
)
echo --- %%f
set /a "filecount+=1"
set /a "totalcount+=1"
)
echo:
echo In "%~dp0" found !totalcount! file^(s^).
)
endlocal
Try it and see if it is what you expected.
Thank you for the help everybody, I've found the solution to the problem and it was very simple. All I needed to do was loop through %1\*.* instead of %1 itself.
#Echo off
if exist %1 (
for %%f in (%1\*.*) do (
echo %%f
)
) else (
echo "That directory does not exist."
)

Moving specific number of files into newly created numbered folders

I currently have around 550 files in a folder with the same format (.csv) and same headers (all started with the letters "YL").
I wonder if there is a way to splits these files (50 files at a time) (order doesn't matter) into numbered folders? (ex. 1, 2, 3, 4, 5) And also create a subsequent folder for the leftover files?
I have found this scripts and tried to modify it for 50 files, but it looks like it only created a the first folder (subdir1)
#echo off
set /a counter=1
set /a filesperfolder=50
cd dir\dir_main
:loopstart
set dirname=subdir%counter%
md %dirname%
echo %dirname%
dir /b | findstr /v /i "subdir*"> %temp%\temp.txt && for /l %%l in (1,1,%filesperfolder%) do #for /f "tokens=1,2* delims=:" %%a in ('findstr /n /r "^" %temp%\temp.txt ^| findstr /r "^%%l:"') do #move %%b %dirname%\%%b >nul
set /a counter=%counter%+1
for /f "tokens=*" %%a in ('type %temp%\temp.txt ^| find /c /v ""') do set _filesmoved=%%a
del %temp%\temp.txt
IF %_filesmoved% LSS 50 goto done
goto loopstart
:done
cls
echo All files were moved!!
pause
exit
I disliked the script you found as it was hard to read and used a temp file to keep track of the list of files. (Also, it evidently doesn't work, so there's that.)
#echo off
SET /a cnt=50
SET /a fnum=0
FOR /F "delims=" %%f IN ('dir /b /a-d *.csv') DO (
CALL :moveFile "%%f"
)
GOTO :end
:moveFile
IF "%cnt%" equ "50" CALL :makeDir
move "%~1" "%fnum%\%~1"
SET /a cnt+=1
GOTO :EOF
:makeDir
SET /a fnum+=1
mkdir %fnum%
SET /a cnt=0
GOTO :EOF
:end
Here is another way to do it. We test if there are still files in the directory, if there is, create a new directory and copy 50 files.
#echo off & setlocal enabledelayedexpansion
set fold_cnt=1
:test
set file_cnt=50
dir /a-d YL*.csv | findstr /IRC:"File(s)"
if %errorlevel% equ 0 (
mkdir !fold_cnt!
) else (
goto :eof
)
for %%i in (YL*.csv) do (
if not !file_cnt! equ 0 (
set /a file_cnt-=1
move /Y "%%i" "!fold_cnt!\%%i"
)
)
set /a fold_cnt+=1
goto test

Equalise the number of files with windows batch

I have a script that is designed to count the number of files with a value in the filename (****_1.jpg), compare it with the number of files with another name (****_2.jpg) and delete the larger number of files so the number of files are equal for each type.
This is what I've got so far
#echo off
setlocal enableextensions
set count1=0
set count2=0
for %%f in (.\seq\*_1.jpg) do set /a count1+=1
echo "1 " %count1%
for %%f in (.\seq\*_2.jpg) do set /a count2+=1
echo "2 " %count2%
if %count1% gtr %count2% (
set /a count=%count2%-%count1%
for /l %%A in (1,1,%count%) do echo "%count2% + %%A _1.jpg"
)
if %count2% gtr %count1% (
set /a count=%count2%-%count1%
for /l %%A in (1,1,%count%) do echo "%count1% + %%A _2.jpg"
)
endlocal
I can get the counts, I make it to my if statements and then nothing happens. What am I missing?
For now I'm trying to echo a list of files I'm about to delete.
In addition to the need for ENABLEDELAYEDEXPANSION, there really is no record of file names from either set. The "count" cannot be used to create the filename, can it?
I put in some code at the top to create a test set. Always referencing THEDIR obviates the need to hardcode a directory name in many places.
When you think it will work, remove echo from the DEL command line.
#echo off
setlocal enableextensions enabledelayedexpansion
set "THEDIR=.\seqtest"
if not exist "%THEDIR%" (mkdir "%THEDIR%")
for /l %%i in (1, 1, 5) do (echo %%i >"%THEDIR%\file_%%i_1.jpg")
for /l %%i in (1, 1, 7) do (echo %%i >"%THEDIR%\file_%%i_2.jpg")
set count1=0
set count2=0
for %%f in ("%THEDIR%\*_1.jpg") do set /a count1+=1
echo "1 " %count1%
for %%f in ("%THEDIR%\*_2.jpg") do set /a count2+=1
echo "2 " %count2%
if %count1% gtr %count2% (
set /a count=%count2%-%count1%
set /a "dcount=0"
for /f "usebackq tokens=*" %%f in (`dir /b "%THEDIR%\*_1.jpg"`) do (
echo DEL "%%~f"
set /a "dcount+=1"
if !dcount! EQU !count! (goto Outa2)
)
for /l %%A in (1,1,%count%) do echo "%count2% + %%A _1.jpg"
)
if %count2% gtr %count1% (
set /a count=%count2%-%count1%
set /a "dcount=0"
for /f "usebackq tokens=*" %%f in (`dir /b "%THEDIR%\*_2.jpg"`) do (
echo DEL "%%~f"
set /a "dcount+=1"
if !dcount! EQU !count! (goto Outa2)
)
)
:Outa2
:TheEnd
exit /b 0
If you want to delete any _1 file that does not exist as an _2 file and vice versa, you could loop over the _1 files and delete any for which no _2 file exists. Then, loop over the _2 files and delete any for which no _1 file exists.
for /f "usebackq tokens=*" %%f in (`dir /b "%THEDIR%\*_1.jpg"`) DO (
set "FN=%%~f"
set "BASE=!FN:~0,-6!"
if not exist "%THEDIR%\!BASE!_2.jpg" (echo DEL "%THEDIR%\!BASE!_1.jpg")
)
for /f "usebackq tokens=*" %%f in (`dir /b "%THEDIR%\*_2.jpg"`) DO (
set "FN=%%~f"
set "BASE=!FN:~0,-6!"
if not exist "%THEDIR%\!BASE!_1.jpg" (echo DEL "%THEDIR%\!BASE!_2.jpg")
)
As I understand this problem, you have two lists of files and you want to delete files from the larger list so both lists have the same number of files. Right? For example:
1_1.jpg 1_2.jpg
2_1.jpg 2_2.jpg
3_1.jpg 3_2.jpg
4_2.jpg
5_2.jpg
In previous example you want to delete 4_2.jpg and 5_2.jpg, correct? If the first list is the larger one, the files must be deleted from it; if both lists have the same number of files, no files be deleted. This solution do that:
#echo off
setlocal
rem Enter to the folder with files
cd seq
rem Get the first list of files
dir /B *_1.jpg > first.txt
rem Merge the first list...
< first.txt (
rem ... with the second list
for %%f in (*_2.jpg) (
rem For each file in second list, read a file from first list
set "first=" & set /P "first="
if not defined first ( rem The second list is larger: cut it
ECHO del "%%f"
)
)
rem If still are files in first list, it is larger: cut it
for /F "delims=" %%f in ('findstr "^"') do ECHO del "%%f"
)
I think, Your method for searching for all *.jpg files is little buggy. You should try this following approach instead. I've modified the code to check the code a little - but you'll get the idea.
#echo off
setlocal EnableDelayedExpansion enableextensions
set count1=0
set count2=0
for /f %%f in ('Dir /s /b "Photo\*.jpg"') do set /a count1+=1
echo "1 " %count1%
for /f %%f in ('Dir /s /b "Photo\*.Png"') do set /a count2+=1
echo "2 " %count2%
if %count1% gtr %count2% (
set /a count=%count2%-%count1%
for /l %%A in (1,1,%count%) do echo "!count2! + %%A _1.jpg"
)
if %count2% gtr %count1% (
set /a count=%count2%-%count1%
for /l %%A in (1,1,%count%) do echo "!count1! + %%A _2.jpg"
)
endlocal
pause >nul
You can change the searching path from - "Photo\*.jpg" to anything in both cases. And this one has given me desired result on the CMD. I Hope this will work fine for you.
...
echo "2 " %count2%
set /a count=count1-count2
set "count=%count:-=%"
if %count1% gtr %count2% (
...
You evidently want to calculate count and need a method to find its absolute value.
simply subtract one vale from the other, then replace any - in the result with nothing.
From the prompt, see set /? for documentation.

How to test if a Zip file is valid in a windows batch file

I am using the command line version of 7-zip and I can use this to test if a zip file is valid by using the t command.
But I'm trying to create a batch file which will cycle through a bunch of zip files in a directory and do one thing if the zip is empty, and another thing if the zip has some files archived in it.
Any pointers how you do this using a batch file?
this may help
#echo off
setlocal enabledelayedexpansion
set "zipPath=C:\temporal\"
set "zipProg=C:\Program Files (x86)\7-Zip\7z.exe"
call:shortIt "%zipPath%", zipPath
call:shortIt "%zipProg%", zipProg
pushd %zipPath%
for /F "tokens=*" %%a in ('dir /b "%zipPath%" ^| find ".zip"') do (
set/a numFiles=0, isOk=0, size=0, compressed=0
for /F "tokens=*" %%i in ('%zipProg% t "%zipPath%%%a"') do (
echo %%i | find /I "ok" >NUL && set/a isOK=1
echo %%i | find /I "files" >NUL && for /F "tokens=2 delims=:" %%n in ("%%i") do set/a numFiles=%%n
echo %%i | find /I "size" >NUL && for /F "tokens=2 delims=:" %%n in ("%%i") do set/a size=%%n
echo %%i | find /I "compressed" >NUL && for /F "tokens=2 delims=:" %%n in ("%%i") do set/a compressed=%%n
)
if !isOk! neq 0 if !numFiles! equ 0 if !size! neq 0 set/a numFiles=1
if !isOk! equ 0 (
echo(
echo(%zipPath%%%a is not an archive or an error ocurred
echo(
) else (
if !numFiles! neq 0 (
echo(%zipPath%%%a contains !numFiles! files [!size! to !compressed!]
) else (
echo(%zipPath%%%a is empty
)
)
)
popd
endlocal
exit/B 0
:shortIt
SetLocal & set "token=%~s1"
EndLocal & set "%2=%token%"

for command is executed only for the first value when a label is inside

I have the script
for /f "delims=" %%i in ('dir "%folder%*.txt" /b /s') do (
set s=%%i
set s=!s:%folder%=!
set new_s=!s:\=!
if "x!new_s!" NEQ "x!s!" (
:ProcessListSource
For /f "tokens=1* delims=\" %%A in ("!s!") do (
if "%%A" NEQ "" (
if "!Folder1!" NEQ "" (
Set Folder1=!Folder1!\!Name!
)else (
Set Folder1=!Name!
)
Set Name=%%A
)
if "%%B" NEQ "" (
set s=%%B
goto :ProcessListSource
)
)
echo Folder is: !Folder1!
echo Name is: !Name!
echo ---------------------
) else (
echo Not a folder !s!
)
)
but it does not work as I would have expected:
The first for is executed only once and also the last echo is printed on the screen.
Given a folder I need the files from subfolders without the given folder and than split them into the folder and file
Ex: folder=C:\test
The for would give me the file C:\test\test1\test2\t.txt
And I need test1\test2 and t.txt
GOTO breaks your FOR /F \ IF context and they can be executed only once.
More simple example:
#echo off
for /l %%S in (1=1=5) do (
echo %%S
goto :inner_label
rem
:inner_label
rem
)
This will print only 1 . Do you really need the GOTO here?
When the parser reads your code, all the code inside your for loop is "considered" as only one command that is readed, parsed and executed. As stated in the npocmaka answer, any goto call takes you out of this "line" of code, ending the process of the for loop.
This is a alternative. Use pushd + xcopy /l /s commands to generate a list of the relative paths of the files.
#echo off
setlocal enableextensions disabledelayedexpansion
set "folder=%cd%"
pushd "%folder%"
for /f "delims=" %%a in ('xcopy /l /s /y * "%temp%"^|findstr /vbr /c:"[0-9]"'
) do for /f "delims=: tokens=1,*" %%b in ("%%~a") do (
echo [%%c] [%%~nxa]
)
popd

Resources