How do I get the current directory name in a windows command prompt inside of FOR loop?

I'm using Win-10 64-bit.

Given the following directory structure on my windows machine...

c:\tmp\Logs_UAT\
'-> folder1
|   '-> test.txt
'-> folder2
    '-> test.txt

...I'm trying to rename all files in each directory by prefixing them with the directory name, to have:

c:\tmp\Logs_UAT\
'-> folder1
|   '-> folder1_test.txt
'-> folder2
    '-> folder2_test.txt

In order to achieve this, I'm looping recursively through files in the %basedir% using FOR and in each directory I'm getting a current directory name using the inner FOR "loop", and then doing a rename. However, current directory is usually not derived correctly. Here's the .bat file which allows to reproduce the issue:

@echo off

set basedir=c:\tmp\Logs_UAT

for /R %basedir% %%I in (*) DO (
cd %%~pI

for %%G in (.) do echo %%~nxG> temp.temp
set /P curdir=<temp.temp
del /f temp.temp

echo.
echo -------------------
echo %%I
dir
echo %curdir%
echo -------------------
)

It outputs the same value for %curdir% for both files:

C:\tmp>test.bat

-------------------
c:\tmp\Logs_UAT\folder1\test.txt
 Datenträger in Laufwerk C: ist OSDisk
 Volumeseriennummer: D280-2DC0

 Verzeichnis von C:\tmp\Logs_UAT\folder1

06.05.2020  19:29    <DIR>          .
06.05.2020  19:29    <DIR>          ..
06.05.2020  19:02                 0 test.txt
               1 Datei(en),              0 Bytes
               2 Verzeichnis(se), 291.684.151.296 Bytes frei
folder2
-------------------
.
-------------------
c:\tmp\Logs_UAT\folder2\test.txt
 Datenträger in Laufwerk C: ist OSDisk
 Volumeseriennummer: D280-2DC0

 Verzeichnis von C:\tmp\Logs_UAT\folder2

06.05.2020  19:29    <DIR>          .
06.05.2020  19:29    <DIR>          ..
06.05.2020  19:02                 0 test.txt
               1 Datei(en),              0 Bytes
               2 Verzeichnis(se), 291.684.151.296 Bytes frei
folder2
-------------------

C:\tmp\Logs_UAT\folder2>

I tried:

  1. Fresh console window
  2. Console and batch file
  3. Sometimes I'm getting the first folder name and sometimes second
  4. Lots of search on the internet

I'd prefer to stick to standard windows utilities as I have to distribute the script to other users which might not have the extra software.

How do I get the current directory name in a windows command prompt inside of FOR loop?


Solution 1:

Indeed DelayedExpansion helped, thanks DavidPostill. Here's the working script:

@echo off
SETLOCAL EnableDelayedExpansion
set basedir=c:\tmp\Logs_UAT

for /R %basedir% %%I in (*) DO (
cd %%~pI

for %%G in (.) do echo %%~nxG> temp.temp
set /P curdir=<temp.temp
del /f temp.temp

echo !curdir!
)

endlocal

Solution 2:

  • For you to get the same result as in your question, in one loop:
@echo off

set "_=echo\ -------------------"
for /D /R "c:\tmp\Logs_UAT" %%I in (*
)do %_% & echo\%%~nxI & dir "%%~nxI" & echo\ %%~nxI & %_%
  • Your output:
 -------------------

 Volume in drive C has no label.
 Volume Serial Number is 32E8-70C5

 Directory of c:\tmp\Logs_UAT\folder1

05/06/2020  02:40 PM    <DIR>          .
05/06/2020  02:40 PM    <DIR>          ..
05/06/2020  02:41 PM                 8 test.txt
               1 File(s)              8 bytes
               2 Dir(s)   3,128,999,936 bytes free
 folder1
 -------------------
 -------------------

 Volume in drive C has no label.
 Volume Serial Number is 32E8-70C5

 Directory of c:\tmp\Logs_UAT\folder2

05/06/2020  02:47 PM    <DIR>          .
05/06/2020  02:47 PM    <DIR>          ..
05/06/2020  02:48 PM                 7 folder2.txt
               1 File(s)              7 bytes
               2 Dir(s)   3,128,999,936 bytes free
 folder2
 -------------------


  1. You don't need to use more than one for loop, use for /D /R, in one loop recursive in all subdirectories, and this makes DelayedExpansion not necessary

  2. Why need to create and delete a file temp.temp in the entire directory using for /D with any additional for loop? When you already have the name of the current folder in your loop (/Recursive in all sub/Directories) stored in the variable %%~nxI (and many others available expansively too), so, for to use in your looping, just use them...

    • Use the FOR variable syntax replacement:
      %~pI        - expands %I to a path only
      %~nI        - expands %I to a file name only
      %~xI        - expands %I to a file extension only
    • The modifiers can be combined to get compound results:
      %~pnI       - expands %I to a path and file name only
      %~pnxI      - expands %I to a path, file name and extension only
    • )do %_% & echo\%%~nxI & dir "%%~nxI" & echo\ %%~nxI & %_%

      Obs.: About using %%~x in directory name observation note in ss64.com:

    • Full Stop Bug
      Although Win32 will not recognise any file or directory name that begins or ends 
      with a '.' (period/full stop) it is possible to include a Full Stop in the middle
      of a directory name and this can cause issues with FOR /D.
    • Parameter expansion will treat a Full Stop as a file extension, so for a directory
      name like "Sample 2.6.4" the output of %%~nI will be truncated to "Sample 2.6" to
      return the whole folder name use %%I or %%~nxI
  3. You don't need to use DelayedExpansion, you can use cmd /v/c echo\!curdir! or echo\%%~nxI

  4. For get output as the same of your code output question, you can set/use a variable for your banner (set _=echo\ ----), adjust this to desired layout output:

    • )do %_% & echo\%%~nxI & dir "%%~nxI" & echo\ %%~nxI & %_%

    Or, in one conventional formatting

    • @echo off
      
      set "_=echo\ -------------------"
      
      for /D /R "c:\tmp\Logs_UAT" %%I in (*)do (
      
      %_%
      echo\%%~nxI
      dir "%%~nxI"
      echo\ %%~nxI
      %_%
      
      )
  5. For one simple and short output option in one line with for /D /R loop, you can try:

    • @echo off
      
      for /d /r "c:\tmp\Logs_UAT" %%I in (*)do set "curdir=%%~nxI" && cmd /v /c " echo\!curdir!"

  • Some further reading:

    [√] Set

    [√] CMD /?

    [√] For Loop

    [√] For /D Loop

    [√] For /R Loop

    [√] DelayedExpansion