betty
betty

Reputation: 77

How to get information about current path %CD% in batch in a FOR loop?

I set an environment variable with several comma separated directory paths and use a FOR loop to set current directory to next directory path in variable. And I try to get current path, but it looks strange about result.

I try to use following code:

set a=C:\test\A,C:\test\B,C:\test\C

for %%i in (%a%) do (
    echo %%i
    echo 1 %CD%
    cd %%i
    echo 2 %CD%
    echo ""
)

And result is:

 C:\test>TEST.BAT
 C:\test\A
 1 C:\test
 2 C:\test
 ""
 C:\test\B
 1 C:\test
 2 C:\test
 ""
 C:\test\C
 1 C:\test
 2 C:\test
 ""

 C:\test\C>

%CD% should be changed after cd %%i. But all echo %CD% output the batch file path C:\test being the current directory on starting the batch file.

How can I get correct current path?

Upvotes: 4

Views: 5358

Answers (1)

Mofi
Mofi

Reputation: 49086

All environment variable references using %variable% in a command block starting with ( and ending with matching ) are replaced by Windows command processor by current value of the referenced environment variable before the command block respectively to command left to the beginning of command block is executed at all.

This means for the FOR loop in posted batch file that the Windows command processor modifies the code during the preprocessing phase to:

for %i in (C:\test\A C:\test\B C:\test\C) do (
echo %i
 echo 1 C:\test
 cd %i
 echo 2 C:\test
 echo ""
)

This output exactly as posted can be seen on running the batch file from within a command prompt window instead of double clicking on batch file with @echo off at top removed or commented out or modified to @echo on.

Please note the replacements of each comma by space in list of directories, both %CD% being replaced by C:\test and modified indentations.

Then the FOR command is executed with this preprocessed command block.

The commands cd %%i in the batch file work, but the environment variable references are replaced already before execution by current value of variable CD which is here C:\test.

Delayed environment variable expansion is needed to see the current directory during execution of the FOR loop.

@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "DirectoryList=C:\test\A C:\test\B C:\test\C"

for %%I in (%DirectoryList%) do (
    echo %%I
    echo 1 !CD!
    cd /D %%I
    echo 2 !CD!
    echo/
)

rem Other commands in batch file perhaps using DirectoryList.
endlocal

But please take into account that an exclamation mark inside a directory/file name is interpreted on having delayed environment variable expansion enabled as beginning/end of a variable reference which could result in unexpected behavior on execution.

An even better code to get the full path of current directory is the usage of one more FOR loop with just . meaning current directory as set and reference the loop variable with modifier %~f to get the full path of current directory.

That makes it possible to avoid the usage of delayed expansion and therefore works also for folder paths containing one or more ! in full path.

Here is a code example for this solution which also creates and removes the directories for demonstration.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Create two directories only for demonstration.
md " %SystemDrive%\Temp\Test" 2>nul
if exist "%SystemDrive%\Temp\Test\" set "DirectoryList=%SystemDrive%\Temp\Test"
md "%SystemDrive%\Temp\Development & (Test)!" 2>nul
if exist "%SystemDrive%\Temp\Development & (Test)!\" set DirectoryList=%DirectoryList% "%SystemDrive%\Temp\Development & (Test)!"

rem One more directory path is added to the list of a directory
rem which does not existing at all (hopefully).
set DirectoryList=%DirectoryList% "%SystemRoot%\Temp\Not existing folder!"

rem Setlocal is used here to push path of current directory on stack.
setlocal

for %%I in (%DirectoryList%) do (
    echo Directory: %%I
    for %%J in (.) do echo Before CD: %%~fJ
    cd /D %%I
    for %%J in (.) do echo  After CD: %%~fJ
    echo/
)

rem Other commands in batch file perhaps using DirectoryList.

rem Restore initial current directory as pushed on stack by second setlocal.
endlocal

rem Delete the directories created at top. The directories are not
rem deleted on existing already on starting the execution of the
rem batch file and containing at least one file or directory.
rd "%SystemDrive%\Temp\Development & (Test)!" 2>nul
rd "%SystemDrive%\Temp\Test" 2>nul
rd "%SystemDrive%\Temp" 2>nul
endlocal

The execution of this batch file results, for example, in following output:

Directory: C:\Temp\Test
Before CD: C:\
 After CD: C:\Temp\Test

Directory: "C:\Temp\Development & (Test)!"
Before CD: C:\Temp\Test
 After CD: C:\Temp\Development & (Test)!

Directory: "C:\Windows\Temp\Not existing folder!"
Before CD: C:\Temp\Development & (Test)!
The system cannot find the path specified.
 After CD: C:\Temp\Development & (Test)!

So there is no problem to handle such an unusual directory name like C:\Temp\Development & (Test)! on using this code as long as delayed environment variable expansion is disabled which is made sure by the second command line which defines with first command line the required execution environment completely for this batch file.

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

  • cd /?
  • echo /?
  • endlocal /?
  • for /?
  • if /?
  • md /?
  • rd /?
  • rem /?
  • set /? ... explains also delayed environment variable expansion on an IF and a FOR example.
  • setlocal /?

See also the articles:

Upvotes: 3

Related Questions