Batch wizardry: Finding a subdir in all parent dirs

As an addition to Using my buildtools here is a batch subroutine to find a subdirectory in any of the parent directories of a script:

:FindInParents
@rem search all parent directories for a subdir and return
@rem the full path to that directory in %result%
setlocal
set parentdir=%1%
set subdir=%2%
:loop
call :GetDir %parentdir%
set parentdir=%result%
if exist %parentdir%\%subdir% goto found
goto loop
:found
endlocal & set result=%parentdir%\%subdir%
goto :eof

:GetDir
rem extract path
setlocal
set result=%~dp1%
rem remove any quotes
set result=%result:"=%
rem add quotes
set result="%result%"
rem remove \ before the closing quote
set result=%result:\"="%
rem remove any quotes
set result=%result:"=%
endlocal & set result=%result%
goto :eof

To use it, you first have to copy it to the script that wants to use it. (You could probably also put it into its own file an call that file but for my purpose that would not work.) Then you call it like this:

call :FindInParents %0% buildtools
@rem The result is returned in the %result% environment variable.

As you can see, it needs two parameters. The first one is the directory from where to start searching. Lazy bastard™ that I am I just take the %0% implicit parameter of the batch file that contains its name. While that actually is a file name and not a directory it will work nonetheless because %0%\buildtools does not exist. The second parameter is the name of the subdirectory to find. So the above looks for a subdirectory called “buildtools” in any of the directories contained in the full filename of the current batch file. Don’t forget to add a

goto :eof

to the end of the main batch code so it will not execute the subroutine as well.

The full batch file I use in GExperts to call a central doBuildProject.cmd script located in the buildtools directory looks like this:

@rem Searches the parent dirctories for the buildtools and calls the doBuildProject.cmd there
@echo off
setlocal
call :FindInParents %0% buildtools
call %result%\doBuildProject.cmd
pause
goto :eof

:FindInParents
@rem search all parent directories for a subdir and return
@rem the full path to that directory in %result%
setlocal
set parentdir=%1%
set subdir=%2%
:loop
call :GetDir %parentdir%
set parentdir=%result%
if exist %parentdir%\%subdir% goto found
goto loop
:found
endlocal & set result=%parentdir%\%subdir%
goto :eof

:GetDir
rem extract path
setlocal
set result=%~dp1%
rem remove any quotes
set result=%result:"=%
rem add quotes
set result="%result%"
rem remove \ before the closing quote
set result=%result:\"="%
rem remove any quotes
set result=%result:"=%
endlocal & set result=%result%
goto :eof