Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

setlocal does pushd/popd?

359 views
Skip to first unread message

charles

unread,
Oct 29, 2005, 11:33:11 AM10/29/05
to
With the following code, setlocal is changing to a target directory then
returning to where it started as if a pushd/popd pair was used. I can't
find any documentation that it should do this (and its driven me crazy
until I thought to include a test in the fragment).

I'm just wondering whether anyone has noticed it/seen anything similar
before.

(Using windows 2000)

==== begin code ====
@echo off&setlocal
rem Function of (maybe) 2 args: 1 = param, 2 = directory
if x%1 == x set blockset=final &goto ENDA1
2>NUL cd /d %1 && (set blockset=final &goto ENDP)
if %1 == early set blockset=%1 &goto ENDA1
if %1 == middle set blockset=%1 &goto ENDA1
echo Unknown blockset mode, using default=final. &set blockset=final
:ENDA1
if not x%2 == x cd /d %2 || echo Unfound directory, can't CD to %2.
rem if errorlevel 1 echo something else
:ENDP
rem test for file in dir.
dir atools.bat
echo Blockset=%blockset%
==== end code ====

William Allen

unread,
Oct 29, 2005, 12:24:22 PM10/29/05
to
"charles" wrote in message

> With the following code, setlocal is changing to a target directory then
> returning to where it started as if a pushd/popd pair was used. I can't
> find any documentation that it should do this (and its driven me crazy
> until I thought to include a test in the fragment).
>
> I'm just wondering whether anyone has noticed it/seen anything similar
> before.

SETLOCAL doesn't change the current folder, but I'd noticed that SETLOCAL
localises the effect of any CD commands in the same way as it localises
environment variable changes, so their effect ceases with the following
ENDLOCAL (or the implied ENDLOCAL at the end of the Batch file).
This applies to nested SETLOCAL commands, too, giving rise to
nesting of CD command effects, thus:

CD C:\InitialFolder
:: C:\InitialFolder is now current
SETLOCAL
CD C:\Folder1
:: C:\Folder1 is now current at SetLocal depth 1
SETLOCAL
CD C:\Folder2
:: C:\Folder2 is now current at SetLocal depth 2
ENDLOCAL
:: C:\Folder1 is once again current now we're back at SetLocal depth 1
ENDLOCAL
:: C:\InitialFolder is now current again with no localisation in force

General idea tested in Win95cmd.exe (Win2000 emulator under
Windows 95/98/ME)

--
William Allen
Free interactive Batch Course http://www.allenware.com/icsw/icswidx.htm
Batch Reference with examples http://www.allenware.com/icsw/icswref.htm
From email address not checked. Contact us at http://www.allenware.com/


charles

unread,
Oct 31, 2005, 7:59:56 AM10/31/05
to
On Sat, 29 Oct 2005 17:24:22 +0100, "William Allen" <_w...@email.com>
wrote:

Well it's neat that it works the way it does and we can let this little
thread be the documentation that MS never published.

Nathan Phillip Brink

unread,
Jun 22, 2022, 10:45:58 AM6/22/22
to
An important observation that I have made is that SETLOCAL/ENDLOCAL does not restore the PUSHD/POPD stack. So if you have a script which uses SETLOCAL and PUSHD, the script will still insert the working directory at the time of the PUSHD into the stack. This disturbs the caller’s state, which you are unlikely to want if you are using SETLOCAL. Thus, I recommend to use a pattern where you script begins with SETLOCAL and then you simply use CD in the script. This way, no matter how the script exits, the caller’s working directory will be restored and the caller’s PUSHD/POPD stack will not be altered.

To see the effects of SETLOCAL followed by PUSHD without any POPD, see this following transcript:

C:\Users\ohnob>TYPE AppData\Local\Temp\xx1.cmd
@ECHO OFF
SETLOCAL
PUSHD %~dp0 || EXIT /B 1

C:\Users\ohnob>PUSHD ..

C:\Users>PUSHD ..

C:\>"%USERPROFILE%\AppData\Local\Temp\xx1.cmd"

C:\>CD "%USERPROFILE%"

C:\Users\ohnob>POPD

C:\>POPD

C:\Users>POPD

C:\Users\ohnob>POPD

C:\Users\ohnob>POPD

You can see that the first POPD I run returns me to the root directory even though I never called PUSHD from that directory. The following is the preferred pattern:

@ECHO OFF
SETLOCAL
CD %~dp0 || EXIT /B 1
0 new messages