WIndows batch script to find the correct parent folder

I have a simple problem that I cannot understand: I want to find the parent folder containing the specific file and create an absolute path to this parent folder - and this needs to be done inside the script package - no powershell, no perl, no python ...

Example: let's say this is my directory tree:

root_parent_path dir0 dir1 file1 dir2 dir21 dir22 dir3 dir31 dir32 

In the above example, root_parent_path is in the form c:\folder1\folder2\ .

The result should be stored in an environment variable, for example RESULT_PATH.

So, if I call any of the following:

 script.batch file1 root_parent_path\dir1\dir2 script.batch file1 root_parent_path\dir1\dir2\dir21 script.batch file1 root_parent_path\dir1\dir3\dir31 

the RESULT_PATH variable must be set to root_parent_path\dir1 , because it is the parent element that contains file1 . (I don't care if there is more than one or not a parent folder - I will be sure that there is only one.)

Help is much appreciated, so much time was wasted on it ...

Note: I would appreciate it if the code was also explained! If the two answers offer a working solution, I will take it with a better explanation.

+4
source share
4 answers

Sorry. There are a couple of questions in your question that I don’t understand.

  • If root_parent_path is a folder located inside the root folder of the drive, as indicated in the directory tree, it should include a backslash in front of its name: \root_parent_path , right? If so, then the result of root_parent_path\dir1 not a relative path, but an absolute one, which starts from the root folder of the disk as follows: \root_parent_path\dir1 , right? Note that the batch file below takes this point and inserts a backslash before the second parameter.

  • As I understand it, you need the first folder in the path specified by the second parameter, which contains the file specified in the first parameter. This batch file does this:

EDIT: This batch file has been modified to accept the full path in the second parameter

 @echo off setlocal EnableDelayedExpansion rem Get drive from second parameter, given or implied for %%a in (%2) do set drive=%%~Da rem Extract each partial path from second parameter and search first parameter into it set return_path= set param2=%2 rem Delete drive from second parameter, if any set param2=%param2:*:=% for %%a in (%param2:\= %) do ( set return_path=!return_path!\%%a if exist %drive%!return_path!\%1 goto continue ) set return_path=PATH NOT FOUND :continue echo %drive%%return_path% 

Remember that this result is an absolute path. The relative path will lead to the above examples:

 script.batch file1 root_parent_path\dir1\dir2 -> .. script.batch file1 root_parent_path\dir1\dir2\dir21 -> ..\.. script.batch file1 root_parent_path\dir1\dir3\dir31 -> ..\.. 

Please note that each folder in the path cannot contain spaces. If necessary, this can be fixed.

Test the program and report the result ...

Antonio

PD . In your ORIGINAL question, you said you want a relative path as output, and put an example with a relative path as input. I noted that your answer is not relative, but absolute without a drive, and that my program suggests this situation. If you answered in the comment that you want an absolute path as input and output, I would do it immediately, but you no longer answer ...

You should note that the relative and absolute path management is completely different, and also that if the drive or drive is implied. If your first question would include the second parameter, as it really is: c:\folder1\folder2\ , this question will not be a problem.

EDIT : A new version that accepts spaces in the second parameter.

 @echo off setlocal EnableDelayedExpansion rem Get drive from second parameter, given or implied for %%a in (%2) do set drive=%%~Da rem Get second parameter removing enclosing quotes, if any set param2=%~2 rem Delete drive from second parameter (from beggining of path until first colon) set param2=%param2:*:=% rem Change possible spaces in the path by another character (I used dollar sign) rem to avoid separate names with spaces at that point set param2=%param2: =$% rem ... of course, dollars must be returned back to spaces later rem Extract each partial path from second parameter and search first parameter into it set return_path= for %%a in (%param2:\= %) do ( set return_path=!return_path!\%%a rem Get back spaces converted into dollars set return_path=!return_path:$= ! rem Enclose file name in quotes (required if path contain spaces) if exist "%drive%!return_path!\%1" goto continue ) set return_path=PATH NOT FOUND :continue echo %drive%%return_path% 

In this case, use quotation marks to enclose the path if it contains spaces:

script.bat file1 "c:\first dir\second dir\dir1\dir2"

+3
source

Getting the absolute path of the parent is trivial.

 @echo off setlocal set result_path=%~dp1 

Getting the relative path of the parent is a little more complicated. There is no built-in way to manage relative paths in batch mode. Here is the simplest solution I could come up with.

 @echo off setlocal for %%F in (":.:%~1\..") do set "result_path=%%~fF" set "result_path=%result_path:*:.:=%" 

Please note that the above code does not confirm the existence of the result. It simply removes the last folder name from the path specified in the first argument.

EDIT

Well, I think I understand your requirements. Given the relative path: "rel_path_root\child1\child2\child3" , find "file1" in each step of the path.

Therefore, you need to check if any of the following conditions exist:

  • "rel_path_root\file1"
  • "rel_path_root\child1\file1"
  • "rel_path_root\child1\child2\file1"
  • "rel_path_root\child1\child2\child3\file1"

The following simple script should do the trick.

 @echo off setlocal enableDelayedExpansion :: Get parameters set "file=%~1" set "myPath=%~2" :: Break myPath into component folders by splitting at \ :: For example: "root dir\dir 1\dir 2" --> "root dir" "dir 1" "dir 2" set "myPath= "!myPath:\=" "!" " :: Eliminate empty folders that result from consecutive or trailing \ set "myPath=!myPath:"" =!" :: Loop through the folders, building the path back up again. :: At each iteration, check if file exists and break if found. set "testPath=" set "resultPath=" for %%F in (!myPath!) do ( if defined testPath (set "testPath=!testPath!\%%~F") else set "testPath=%%~F" if exist "!testPath!\!file!" ( set "resultPath=!testPath!" goto :break ) ) :break :: print the result set resultPath 

This will not work with a UNC loop, for example, \\server\folder1\folder2 , and will not work with a relative path consisting only of the drive letter C: . But besides this, he must work with any absolute or relative path.

+1
source

Something like that?

 @echo off set file=%1 set dir=%2 :LOOP if exist %dir%\%file% ( setx RESULT_PATH %CD% ) else ( cd.. goto :LOOP ) 
0
source

This could also be a solution:

 @echo off rem save current dir pushd "%cd%" rem go to specified folder cd "%2" :loop IF EXIST "%1" ( rem found existing file call :relative_path return_path "%cd%" goto :end_loop ) rem trying to go to upper dir. if it succedes, cd_prec != cd set cd_prec=%cd% cd .. IF NOT "%cd%" == "%cd_prec%" goto :loop set return_path=NOT FOUND goto :end_loop rem function to extract \folder1\folder2\etc from c:\folder1\folder2\etc :relative_path <resultVar> <pathVar> set "%~1=%~p2" exit /b ) :end_loop popd echo %return_path% 

The path you specify can be absolute or relative, and it returns as the absolute path where the file is located, and (if necessary) also the path relative to the specified directory, and it supports files and names with spaces. I just use the basic commands, but I think this is what you are looking for.

 C:\Users\user\code\cmd>mkdir c:\folder1\folder2\dir1 C:\Users\user\code\cmd>copy nul c:\folder1\folder2\dir1\file1 C:\Users\user\code\cmd>mkdir c:\folder1\folder2\dir1\dir2\dir21 C:\Users\user\code\cmd>mkdir c:\folder1\folder2\dir1\dir2\dir31 C:\Users\user\code\cmd>script.cmd file1 c:\folder1\folder2\dir1\dir2\ \folder1\folder2\dir1 C:\Users\user\code\cmd>script.cmd file1 c:\folder1\folder2\dir1\dir2\dir21 \folder1\folder2\dir1 C:\Users\user\code\cmd>script.cmd file1 c:\folder1\folder2\dir1\dir2\dir31 \folder1\folder2\dir1 C:\Users\user\code\cmd>cd c:\folder1\folder2\dir1\dir2\dir21 C:\folder1\folder2\dir1\dir2\dir21>script.cmd file1 . \folder1\folder2\dir1 etc... 

they all return the same relative path, without a disk label, I'm not sure, but I think this is what you are looking for. My post before this edit would return the absoulte path (for example, c:\folder1\folder2 ) and the relative path ( ..\..\. ), Starting with root_parent_path .

0
source

Source: https://habr.com/ru/post/1446205/


All Articles