4

我有一个我无法弄清楚的简单问题:我想找到一个包含某个文件的父文件夹,并生成该父文件夹的绝对路径 - 这需要在批处理脚本中完成 - 没有 powershell,没有perl,没有蟒蛇...

例如,假设这是我的目录树:

  root_parent_path
    dir0
    dir1
      file1
      dir2
        dir21
        dir22
      dir3
        dir31
        dir32

在上面的例子中,root_parent_path是 form c:\folder1\folder2\

结果应存储在环境变量中,例如 RESULT_PATH。

因此,如果我拨打以下任何电话:

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

变量 RESULT_PATH 应该设置为root_parent_path\dir1,因为那是包含它的父级file1。(我不在乎是否有多个父文件夹或没有父文件夹 - 我会确保只有一个。)

非常感谢您的帮助,为此浪费了很多时间...

注意:如果还解释了代码,我将不胜感激!如果两个答案提供了可行的解决方案,我会选择一个解释更好的答案。

4

4 回答 4

3

打扰一下。你的问题有几点我不清楚。

  • 如果root_parent_path是放置在磁盘根文件夹内的文件夹,如您在目录树中指出的那样,那么它必须在其名称前包含一个反斜杠:\root_parent_path,对吗?如果这是真的,那么结果root_parent_path\dir1不是相对路径,而是从磁盘的根文件夹开始的绝对路径:,对吗?请注意,下面的批处理文件假定这一点并在第二个参数之前插入反斜杠。\root_parent_path\dir1

  • 据我了解,您希望第二个参数给出的路径中的第一个文件夹包含第一个参数中给出的文件。这个批处理文件这样做:

编辑:此批处理文件已被修改为在第二个参数中接受完全限定的路径

@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%

请记住,此结果是绝对路径。上面示例中的相对路径结果将是这些值:

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     ->      ..\..

请注意,路径中的每个文件夹不能包含空格。如果需要,这可能是固定的。

测试程序并报告结果...

安东尼奥

PD - 在您的原始问题中,您说您想要一个相对路径作为输出,并以相对路径作为输入的示例。我注意到您的回答不是相对的,而是绝对的,没有驱动器,并且我的程序假设了这种情况。如果您在评论中回答您希望将绝对路径作为输入和输出,我会立即这样做,但您不再回答......

您必须注意,相对路径管理和绝对路径管理是完全不同的,而且如果磁盘驱动器是给定的或暗示的。如果您的第一个问题将包含第二个参数,因为它实际上是: c:\folder1\folder2\,那么这一点不会有问题。

编辑:在第二个参数中接受空格的新版本。

@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%

在这种情况下,如果路径包含空格,请使用引号将路径括起来:

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

于 2012-11-16T08:07:48.413 回答
1

获取父级的绝对路径是微不足道的。

@echo off
setlocal
set result_path=%~dp1

获取父级的相对路径有点棘手。没有内置方法可以批量操作相对路径。这是我能想到的最简单的解决方案。

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

请注意,上面的代码不验证结果的存在。它只是从第一个参数中提供的路径中删除最后一个文件夹名称。

编辑

好的,我想我明白你的要求了。给定一个相对路径: ,在路径的每个步骤中"rel_path_root\child1\child2\child3"查找。"file1"

所以需要测试是否存在以下情况:

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

下面的简单脚本应该可以解决问题。

@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

这不适用于 UNC 路径\\server\folder1\folder2,也不适用于仅包含驱动器号的相对路径C:。但除此之外,它应该适用于任何绝对或相对路径。

于 2012-11-15T12:54:17.587 回答
0

像这样的东西?

@echo off
set file=%1
set dir=%2
:LOOP
if exist %dir%\%file% (
setx RESULT_PATH %CD%
) else (
cd..
goto :LOOP
)
于 2012-11-15T11:54:35.827 回答
0

这也可能是一个解决方案:

@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%

您指定的路径可以是绝对路径或相对路径,它返回找到文件的绝对路径和(如果需要)相对于指定目录的路径,它支持带空格的文件和名称。我只是使用基本命令,但我认为这就是你要找的。

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...

它们都返回相同的相对路径,没有磁盘标签,我不确定,但我认为这就是你要找的。我在此编辑之前的帖子将返回绝对路径(如c:\folder1\folder2)和从 开始的相对路径(..\..\.root_parent_path

于 2012-11-18T17:26:50.920 回答