3

I have read many questions and answers about pushd here and on other sites, the overwhelming majority of them referring to issues with UNC paths. However, I've got a different problem I haven't seen a single hint about.

Using Windows 10 x64 Enterprise (Version 1809), I am executing the following batch file from within a console window:

@echo off
setLocal EnableDelayedExpansion
set DestDir=c:\windows
pushd %DestDir%

My problem is that pushd seems to be executed in the wrong way or not at all. That means that I am not in c:\windows when the batch file has been run, but still in the directory I was in before running it.

I have tried several things in a desperate attempt to understand the problem (knowing that those tests didn't make sense):

  • put c:\windows in quotes (set DestDir="c:\windows")
  • put %DestDir% in quotes (pushd "%DestDir%")
  • used ! instead of % because delayed expansion is on, i.e. pushd "!DestDir!"
  • started the console window I ran the batch file from within as Administrator

However, when I do not turn on delayed expansion, pushd works as expected. In other words, after having run the following batch file

@echo off
set DestDir=c:\windows
pushd %DestDir%

I indeed have been beamed into c:\windows regardless of the directory I have been in before running the batch file.

I suppose that I am quite silly at the moment, but I can't wrap my head around this for the life of me. So could anybody please explain why pushd fails if delayed expansion is active?

Binarus
  • 4,005
  • 3
  • 25
  • 41
  • 3
    the explanation is simple (but not intuitive): if you have a `setlocal`, there is an implicit `endlocal` when the script ends, which also means, there's a `popd`. – Stephan May 21 '19 at 19:46
  • 5
    @Stephan: not exactly... Each `endlocal` restores the directory saved by the last `setlocal` like if the current dir were an environment variable! See [this topic](https://www.dostips.com/forum/viewtopic.php?f=3&t=4436). The same behavior happen with `cd` – Aacini May 21 '19 at 19:52
  • @Stephan Thanks, didn't think about that. But the issue is that the directory is not changed *within* the batch file as well. To be honest, this is actually my problem (some code of the batch file relies on being in the right directory and fails currently). I'll investigate if the behavior you mentioned could somehow occur within the batch file. – Binarus May 21 '19 at 20:11
  • 3
    In addition to @Aacinis hint it is to mention that while the previous dir is restored the pushd stack is **not** affected. View `$+` in prompt or issue pushd without args. –  May 21 '19 at 20:45
  • @Stephan I've investigated, and you are right! This is a good example why over-simplifying the actual problem might introduce a new one. I have inserted some `echo %CD%` and seen that `pushd` seems to work. I now have to investigate why the code which relies on being in a certain directory fails. And if you make your comment an answer, I'll accept it. – Binarus May 21 '19 at 21:03

1 Answers1

2

The reason for your problem was already discussed in the comments, but there was no solution so far.
You can overcome the issue by an explicit endlocal:

REM @echo off
setLocal EnableDelayedExpansion
set DestDir=c:\windows
endlocal & pushd %DestDir%

The last line is parsed in one go, so %DestDir% is replaced to its value (before endlocal) before executing the whole line (run with echo on to watch).

Stephan
  • 53,940
  • 10
  • 58
  • 91