How do I get the equivalent of dirname() in a batch file?

I'd like to get the parent directory of a file from within a .bat file. So, given a variable set to "C:\MyDir\MyFile.txt", I'd like to get "C:\MyDir". In other words, the equivalent of dirname() functionality in a typical UNIX environment. Is this possible?


Solution 1:

for %%F in (%filename%) do set dirname=%%~dpF

This will set %dirname% to the drive and directory of the file name stored in %filename%.

Careful with filenames containing spaces, though. Either they have to be set with surrounding quotes:

set filename="C:\MyDir\MyFile with space.txt"

or you have to put the quotes around the argument in the for loop:

for %%F in ("%filename%") do set dirname=%%~dpF

Either method will work, both at the same time won't :-)

Solution 2:

If for whatever reason you can't use FOR (no Command Extensions etc) you might be able to get away with the ..\ hack:

set file=c:\dir\file.txt
set dir=%file%\..\

Solution 3:

The problem with the for loop is that it leaves the trailing \ at the end of the string. This causes problems if you want to get the dirname multiple times. Perhaps you need to get the name of the directory that is the grandparent of the directory containing the file instead of just the parent directory. Simply using the for loop technique a second time will remove the \, and will not get the grandparent directory.

That is you cannot simply do the following.

set filename=c:\1\2\3\t.txt
for %%F in ("%filename%") do set dirname=%%~dpF
for %%F in ("%dirname%") do set dirname=%%~dpF

This will set dirname to "c:\1\2\3", not "c:\1\2".

The following function solves that problem by also removing the trailing \.

:dirname file varName
    setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
    SET _dir=%~dp1
    SET _dir=%_dir:~0,-1%
    endlocal & set %2=%_dir%
GOTO :EOF

It is called as follows.

set filename=c:\1\2\3\t.txt
call :dirname "%filename%" _dirname
call :dirname "%_dirname%" _dirname