我遇到一个我无法弄清楚的简单问题:我想找到一个包含某个文件的父文件夹,并生成该父文件夹的绝对路径 - 这需要在批处理脚本中完成 - 否powershell,没有perl,没有python ......
示例,说这是我的目录树:
root_parent_path
dir0
dir1
file1
dir2
dir21
dir22
dir3
dir31
dir32
在上面的示例中,root_parent_path
的格式为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
的父级。 (我不在乎是否有一个或多个父文件夹 - 我会确保只有一个。)
非常感谢帮助,浪费了很多时间......
注意:如果代码也被解释,我将不胜感激!如果两个答案提供了可行的解决方案,我会选择一个更好的解释。
答案 0 :(得分: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 - 在您的 ORIGINAL 问题中,您说要将相对路径作为输出,并使用相对路径放置一个示例作为输入。我注意到你的答案不是相对,而是绝对没有驱动,我的程序就是这种情况。如果您在评论中回答您希望绝对路径作为输入和输出,我会立即执行此操作,但您不再回答...
您必须注意 relative 和绝对路径管理完全不同,并且如果磁盘驱动器给定或暗示。如果您的第一个问题包含第二个参数,因为它确实是: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"
答案 1 :(得分: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
这不适用于像\\server\folder1\folder2
这样的UNC路径,也不适用于除了驱动器号C:
之外的相对路径。但除此之外,它应该适用于任何绝对或相对路径。
答案 2 :(得分:0)
这样的东西?
@echo off
set file=%1
set dir=%2
:LOOP
if exist %dir%\%file% (
setx RESULT_PATH %CD%
) else (
cd..
goto :LOOP
)
答案 3 :(得分: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%
您指定的路径可以是绝对路径或相对路径,它既返回找到文件的绝对路径,也返回相对于指定目录的路径(如果需要),并且它支持带空格的文件和名称。我只是使用基本命令,但我认为这正是你要找的。 p>
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
开始返回absoulte路径(如..\..\.
)和相对路径(root_parent_path
)。