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:
- Fresh console window
- Console and batch file
- Sometimes I'm getting the first folder name and sometimes second
- 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
-------------------
-
You don't need to use more than one
for
loop, usefor /D /R
, in one loop recursive in all subdirectories, and this makesDelayedExpansion
not necessaryFOR /R - Loop through files (recursively) FOR /D - Loop through several folders/directories
Rem :: Set your folder /Directory /Recursively tree starting at "c:\tmp\Logs_UAT" For /D /R "c:\tmp\Logs_UAT"
-
Why need to create and delete a file
temp.temp
in the entire directory usingfor /D
with any additionalfor
loop? When you already have the name of the current folder in your loop (/R
ecursive in all sub/D
irectories) 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
indirectory
name observation note inss64.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
-
You don't need to use
DelayedExpansion
, you can usecmd /v/c echo\!curdir!
orecho\%%~nxI
-
That's exactly what your code is doing in your question (and answer), you are using multiple
for
loops, where theDelayedExpansion
will not be necessary if you used a singlefor /D /R
when using%%~nxI
For the same result and use on a selected line, if you are using one or more
for
loops, you can also enableDelayedExpansion
at run time usingcmd /v /c echo\!curdir!
expanding the variable value in that time. )do set "curdir=%%~nxI" && cmd /v /c " echo\!curdir!"
-
-
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 %_% )
-
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