Capturing the current directory from a batch file


Sometimes people go to great lengths to get information which is available in a much simpler way. We saw it a few days ago when we found a 200+-line C# program that could be replaced with a 90-byte batch file. Here's another example of a rather roundabout way of capturing the current directory from a batch file.

The easy way is to use the %CD% pseudo-variable. It expands to the current working directory.

set OLDDIR=%CD%
.. do stuff ..
chdir /d %OLDDIR% &rem restore current directory

(Of course, directory save/restore could more easily have been done with pushd/popd, but that's not the point here.)

The %CD% trick is handy even from the command line. For example, I often find myself in a directory where there's a file that I want to operate on but... oh, I need to chdir to some other directory in order to perform that operation.

set _=%CD%\curfile.txt
cd ... some other directory ...
somecommand args %_% args

(I like to use %_% as my scratch environment variable.)

Type SET /? to see the other pseudo-variables provided by the command processor.

Comments (37)
  1. sil says:

    That is undeniably useful, but more often I find myself wanting to find the directory that a specific batch file is in from inside that batch file, which is a bit more awkward.

    Half the time I end up doing something like this:

    :: Change to the directory that this batch file is in

    :: NB: it must be invoked with a full path!

    for /f %%i in ("%0") do set curpath=%%~dpi

    cd /d %curpath%

  2. Ryan says:

    Why not use pushd/popd? No need to use an environment variable at all.

    pushd … some other directory …

    .. do stuff ..

    popd &rem restore current directory

  3. Raymond Chen says:

    Um, try reading past the third paragraph.

  4. Ryan says:

    Doh! Sorry.

  5. waaaay back says:

    I’ve written some stuff for myself that stores the current directory to a file on the current drive.

    A program reads that file, and switches to that directory on the current drive. Very handy for

    1. Crash recovery on pre-XP machines

    2. Getting back to where I was on my Laptop.

    Ryan

    Raymond stated

    "

    (Of course, directory save/restore could more easily have been done with pushd/popd, but that’s not the point here.)

    "

  6. Centaur says:

    The post under the second link is useful because it solves the general problem of capturing output from an external program. %CD% is an easier solution but only for a specific problem of getting the current directory.

  7. ac says:

    >

    More often I find myself wanting to find the directory that a specific batch file is in from inside that batch file, which is a bit more awkward.

    :: Change to the directory that this batch file is in

    :: NB: it must be invoked with a full path!

    for /f %%i in ("%0") do set curpath=%%~dpi

    cd /d %curpath%

    <<

    This is a bit simpler:

    %0

    cd %0..

    cd /d %0..

    The first two lines are for 9x which doesn’t support the /d flag, only the third line is required for NTx. This nifty solution was originally found at alt.msdos.batch.nt.

  8. CornedBee says:

    The best way to do this stuff is, IMHO, to install Cygwin or similar and write Bash scripts.

  9. ca says:

    Works as well:

    cd /d %~dp0

  10. Mike Dimmick says:

    If you want to know where the batch file lives: %~dp0

    %0 is the name of the batch file. ~dp gives you the drive and path of the specified argument.

    I use this technique a lot for automating eMbedded Visual C++ builds. The command-line build environment is pretty tricky to use for Windows CE, so I just use evc /make. Well, actually I use a C# program I wrote which looks up in the registry where eVC is installed and runs evc.com from either eVC 3.0 or eVC 4.0 depending on the command line argument passed, or if no version is specified, on the first line of the workspace file.

    For most of my projects I’ve now got down to the holy grail of single-command automated builds through a variety of batch files and simple utilities like that one. The ‘buildme’ batch file rebuilds all the components from source then builds a Windows CE installation CAB for potentially many platforms.

  11. mathias says:

    Regarding pushd/popd: is there a way to list the content if its stack? I always seem to forget what I’ve pushd’d and if popd will actually take me back where I want.

  12. BlackTigerX says:

    you can also use SUBST…

  13. "Regarding pushd/popd: is there a way to list the content if its stack? I always seem to forget what I’ve pushd’d and if popd will actually take me back where I want. "

    Don’t know if you can get a list of the stack contents, but you can set the prompt to show you how deep the stack is by adding $+ to the prompt. See prompt /? for more info of course. But would be nice to output what the stack is too.. anybody who knows if that is possible?

  14. Greg says:

    Didn’t know that one (%CD%).

    I use %TEMP% now and then too, if I want to try out a code snippet but don’t need to keep the project. I’ll save the project to %TEMP%.

    I’m sure you all know this, but you can use . for

    the current directory and .. for the parent of the current directory. Very handy.

  15. Mark Ingalls [exmsft] says:

    "is there a way to list the content if its stack?"

    On windows xp, issuing pushd with no args lists the contents of the stack:

    C:temp>pushd "Documents and Settings"

    C:Documents and Settings>pushd

    C:temp

    C:Documents and Settings>pushd tools

    C:tools>pushd

    C:Documents and Settings

    C:temp

    on other versions of windows, YMMV.

  16. Mr. Ed says:

    You can use pushd + %CD% to get the canonical version of a path, too:

    pushd %MYPATH%

    set MYPATH=%CD%

    popd

  17. Jeremy Morton [MSFT] says:

    In a lot of my CMD scripts, I use the %RANDOM% pseudo-variable; it’s great for creating temp files that you don’t want to collide with other instances of your script. E.g. foo.cmd:

    @if DEFINED _echo @( echo on ) else @( echo off )

    :RandomFile

    set __foo_ScratchFile=%TEMP%foo.scratch.%RANDOM%.txt

    if EXIST %__foo_ScratchFile% goto RandomFile

    (

    echo Scratch foo content!

    echo Second line of content

    echo.

    echo Fourth line

    ) > %__foo_ScratchFile%

    if EXIST %__foo_ScratchFile% del /f/q %__foo_ScratchFile% > nul 2>&1

    There’s a fair amount of fun CMD script fun in there… :)

  18. Jeremy Morton [MSFT] says:

    A commenter on the link that Raymond pointed to up top says:

    —–

    If you’ve got Cygwin installed, you can use its ‘date’ command to get hold of a suitable suffix for logfiles, e.g.:

    for /f "delims=" %%i in (‘c:cygwinbindate +%%Y%%m%%d.%%H%%M%%S’) do set fileSuffix=%%i

    Note the doubling of the %-marks in the format string. You need to do this, or you’ll end up with a suffix of "mHS".

    —–

    You don’t need the for loop in this example, either. In other situations, for /f is very, very useful, but for this, you can just do this [assuming your locale is English (United States)]:

    set fileSuffix=%DATE:~-4%%DATE:~4,2%%DATE:~7,2%.%TIME:~0,2%%TIME:~3,2%%TIME:~6,2%

    @REM %TIME% Puts a leading space on hours if < 10, change to 0

    set fileSuffix=%fileSuffix: =0%

    The big drawback is that %DATE% and %TIME% are formatted according to your locale, so this method of parsing isn’t universal. :/

  19. thekulp.com says:

    <p>… I don’t need a verbose language to program in!</p>
    <p>For the longest time I thought that the equivalent of backticks in UNIX (substituting `*cmd*` with the output of *cmd*) was impossible in Windows. It probably is impossible pre-Win2k, but I ha

  20. Eric TF Bat says:

    You have to admit that one reason for the weird circumlocutions you see in people’s batch code is that the documentation is so woeful. Suppose I want to know how to extract the year from the DATE pseudovariable. What’s the command to get that information? Why, it’s explained in the help for the SET command. How obvious. And if I want to know the matching syntax for splitting the %0, %1 and other variables, where’s that explained? So far the answer seems to be: in Raymond Chen’s weblog.

    I would dearly like to see something that explains all of it – pseudovars, the arcane and inane rules of expansion, what registry setting to tweak if you want command completion — everything. I suggest the ideal name would be MAN – Microsoft’s Arcane Nuances.

  21. Alex Blekhman says:

    2Eric TF Bat

    I found this Usenet group "

    microsoft.public.win2000.cmdprompt.admin" invaluable when dealing with CMD.EXE. There is much esoteric knowledge shared out there by very skillful individuals.

  22. James says:

    On a somewhat related topic, since a number of people have mentioned CD /D:

    Why isn’t /D idempotent (on Windows 2000, anyway)?

    CD /D /D <fullPath>

    does nothing.

    This is problematic for scripts, because you don’t know if someone has used doskey to alias CD to CD /D, and AFAICT there’s no way for a script to unload doskey aliases.

  23. ilm says:

    Try running %windir%helpntcmds.chm – don’t know if it covers everything though.

  24. Loz says:

    On NT4:

    > echo %CD%

    %CD%

  25. Ben Cooke says:

    Loz,

    If I’m reading the documentation correctly, %CD% is a pseudo-variable only available to set. It’s not a real environment variable, so it’s not generally available.

    You can make it generally available like this, however:

    set CD=%CD%

    …but you must remember to update the variable every time you change the current working directory, of course.

    It’s been so long since I wrote batch files. I remember writing a pretty text-based menu system using ANSI.SYS and CHOICE in MS-DOS many moons ago. Fun times. Lots of the new additions made in CMD would have made life so much easier for me writing that!

  26. Ben Cooke says:

    Scratch my last comment. I didn’t actually test to see if echo would honour the pseudo-variable on my Windows 2000 system, but it did. I think I’ll refrain from commenting any further on this, because I’m just going to end up embarassing myself. ;)

  27. Marcelo says:

    Yes!

  28. DavidE says:

    Why the heck can’t we just have backquotes in Windows batch? It’s not like it’s a new idea. I’ve been using them since I was a teenager, and I’m ancient!

  29. Raymond Chen says:

    You can – see "for /?" and "usebackq".

    The problem is how to add these features without breaking existing batch files.

  30. GAM says:

    Don’t forget to handle spaces in path and file names. Note for example the difference between how cd and chdir operates with and without command extensions enabled.

  31. DavidE says:

    You miss my point, Raymond. I should be able to use backquotes with "set" or even some random exe like notepad, as in "notepad.exe lookformyfiles.exe". I don’t mind having to call some "setbatchoptions" commmand to turn the feature on if I have to. Don’t get me wrong – I’ll use "for" to do this, but I’m much more likely to require every machine I work on to have perl or some other tool I have to support.

  32. Raymond Chen says:

    But if you turn the feature on, it will break batch files that weren’t written to be compatible with "setbatchoptions". For example, a batch file that says

    echo Hello'
    <br>
    <br>will now get an &quot;unmatched backquotes&quot; error instead of printing
    Hello’. Maybe batch file backwards compatibility isn’t important to you, but it is to an awful lot of corporate system administrators who deploy batch files throughout their company.

    If you want ksh you know where to find it.

    http://weblogs.asp.net/oldnewthing/archive/2005/01/24/359496.aspx

  33. The problem: where’s the script?

    Your script or application needs to locate other files or directories…

  34. Otherwise file names won’t resolve.

Comments are closed.