Batch for loop not recognizing its own variable

I am currently programming a program that can compile all images into a small directory. I've been trying to use this code and figure out why it keeps breaking to no end. In CMD, it says that "%~xr was unexpected at this time" even though the variable I assigned to this for loop was... "%%r." I'm using a Batch file, meaning that %%r should be used instead of %r. And in fact, in the code, I did indeed use "%%~xr" for the file extension of "%%r," so I don't know what's going on. Could someone help me?

Note: I'm not very experienced, and am just using what I come up with in this sample, so bear with the jankyness of it, please.

@echo off
set /a counter=1
set name=All Images
mkdir "%cd%/%name%" >nul
rem This creates a directory called "%cd%/All Images." "%cd%" is the batch file's current directory.
for /f "tokens=*" %%r in (allimages.log) do (
    set "extension=%%~xr"
    rem Set the variable "extension" to whatever the file extension that was picked up from "allimages.log." This is important for the "call" command as it will break if given a for loop's variable.
    call :isuckatcoding
    if not exist "%cd%\%name%\%%~xr\%%~nxr" (
        rem This is saying if not exist "%cd%\All Images\[file extension]\[file name and extension]"
        copy "%file%" "%cd%\%name%\%%~xr"
    ) else (
        set /a counter+=1
        copy "%%r" "%cd%\%name%\%%~xr\%%~nr (%counter%)%%~xr"
    )
    rem This code is supposed to rename the file being copied if there already exists that file name in the directory being copied to. However, this code never seems to work for some reason.

)

:isuckatcoding
if not exist "%cd%\%name%\%extension%" (mkdir "%cd%/%name%/%extension%")
exit /b
rem Creates a ".jpg" directory if one doesn't exist.

Here's what's inside "allimages.log:"

C:\Users\Rando\Desktop\Need to Sort\Batch Files\booba test time baby\New folder\test.jpg
C:\Users\Rando\Desktop\Need to Sort\Batch Files\booba test time baby\New folder (2)\testa.jpg

I have verified that both files do still exist. I also realize that it looks like the renaming-related code isn't being used, but most of the time the files are named just "test.jpg."


Batch for loop not recognizing its own variable

To use some value inside a function, which is some file, eXtention, folder, variable, etc.. It is necessary to pass this item to him, he will not access the already defined variables if you don't to pass something that it is to be used within the function:

:: call :label parameter1 parameter2 ... parameterN 

call %:^) "%_dir%\%%~xr"

%:^)
echo\ heyo, be sure that I can use %~1 for do my job  
exit /b  

About your code:

You can do it with and without using a label/function, but for both options, you will need enabledelayedexpansion to update the value of its !counter! variable inside for()do if()else() at runtime.


  • Without :label
@echo off

set "_dir=%~dp0All Images"
setlocal enabledelayedexpansion
2>nul mkdir "%_dir%" & set "_cnt=1"

for /f usebackq^delims^= %%r in (.\allimages.log) do 1<nul 2>nul (
     md "%_dir%\%%~xr" & if not exist "%_dir%\%%~xr\%%~nxr" >nul (
         copy "%%~r" "%_dir%\%%~xr\.") else >nul (set /a "_cnt+=1" 
         copy "%%~r" "%_dir%\%%~xr\%%~nr (!_cnt!)%%~xr") )

endlocal & goto :eOf

  • The same code in conventional layout:
@echo off

setlocal enabledelayedexpansion

set "_cnt=1"
set "_dir=%~dp0All Images"
2>nul mkdir "%_dir%"


for /f "usebackq delims=" %%r in (allimages.log) do (
     md "%_dir%\%%~xr" 2>nul 
     if not exist "%_dir%\%%~xr\%%~nxr" (
         copy "%%~r" "%_dir%\%%~xr" >nul
       ) else  (
         set /a "_cnt=!_cnt! + 1" 
         copy "%%~r" "%_dir%\%%~xr\%%~nr (!_cnt!)%%~xr" >nul
        )
    )

endlocal & goto :eOf

  • With :label
@echo off

setlocal enabledelayedexpansion

set "_cnt=1"
set "_dir=%~dp0All Images"
2>nul mkdir "%_dir%"

for /f "usebackq delims=" %%r in (allimages.log) do (
    if not exist "%_dir%\%%~xr\%%~nxr" (
         call %:^) "%_dir%\%%~xr" 
         copy "%%~r" "%_dir%\%%~xr" >nul 
       ) else (
         set /a "_cnt=!_cnt! + 1" 
         copy "%%~r" "%_dir%\%%~xr\%%~nr (!_cnt!)%%~xr" >nul
        )
    )

%:^)
if not "%~1" == "" (
      if not exist "%~1" md "%~1" 
      exit /b
    ) else (
      endlocal
    )

:: "%~dp0" => Expand to "Drive:\Folder\Path" to yourfile.bat
if you current work directory is the same from your bat, you can also use: 

set "_dir=%~dp0All Images"
:: 2>nul omit/suppress output to any warning/error
if folder does not exist it will be created, if it exists, omit the error...
2>nul mkdir "%_dir%"

  • If you want to create file extensions as folders without the dot (.), I suggest something like:
@echo off

set "_dir=%~dp0All Images"
setlocal enabledelayedexpansion
2>nul md "%_dir%" & set "_cnt=1"

for /f usebackq^delims^= %%r in (
.\allimages.log) do 1<nul 2>nul (
     ;set "_eXt=%%~xr" & ;call md "%_dir%\!_eXt:.=!"
     ;if not exist "%_dir%\!_eXt:.=!\\%%~nxr" >nul (
         ;copy "%%~r" "%_dir%\!_eXt:.=!\\.") ;else (set/a "_cnt+=1" 
         <con: copy "%%~r" "%_dir%\!_eXt:.=!\%%~nr (!_cnt!)%%~xr"))

tree /a & set /p "= Files duplicated: !_cnt! | Files copied: " <nul  
dir /a-d /b /s "All Images" | find /v /c "" & timeout -1 & endlocal
  • The output in my test scenario is:
Folder PATH listing
Volume serial number is 02DBAE18 9A8E:862E
C:.
\---All Images
    +---gif
    +---jpeg
    +---jpg
    \---png
Files duplicated: 34 | Files copied: 102

Some further reading:

[√] If /?

[√] Set /?

[√] For /?

[√] For /F

[√] Redirection |, <, > 2>, ...

[√] Goto :Label | Call :Label

[√] DelayedExpansion (Refer: !Expand_RunTime_Variable!)

[√] Set variable=variable:substrings | DOS - String Manipulation

How does the Windows Command Interpreter cmd.exe Parse Scripts