批量获取绝对路径的相对路径

时间:2018-02-13 11:26:11

标签: batch-file

如何批量转换绝对路径到相对路径?我有一个目录A和参考目录B的绝对路径,我需要A相对于B的路径。例如,以下批处理脚本应打印..\other\somedir\

setlocal enabledelayedexpansion
set referencePath=C:\Users\xyz\project\
set absolutePath=C:\Users\xyz\other\somedir\
set relativePath=...
echo %relativePath%

我尝试了relativePath=!absolutePath:%referencePath%=!,但这会产生绝对路径C:\Users\xyz\other\somedir\

我需要类似于python函数os.path.relpath的东西:

>>> os.path.relpath("C:\\Users\\xyz\\other\\somedir", "C:\\Users\\xyz\\project\\")
"..\\other\\somedir"

我需要这个,因为我有一个批处理文件,命令行参数类似于上面的文件名。此批处理文件创建另一个批处理文件startup.bat,该文件设置一些环境变量并启动应用程序。可以通过网络调用startup.bat,因此我必须使用相对路径。对于绝对路径,环境变量将指向错误机器上的文件。

6 个答案:

答案 0 :(得分:1)

这是一个快速的黑客攻击:

@echo off
setlocal enabledelayedexpansion
set referencePath=C:\Users\xyz\project\
set absolutePath=C:\Users\xyz\other\somedir\
set relativePath=
:LOOP
for /F "tokens=1 delims=\" %%a in ("%referencePath%") do (set ref=%%a)
for /F "tokens=1 delims=\" %%a in ("%absolutePath%") do (set rel=%%a)
if /i !ref!==!rel! (
    set referencePath=!referencePath:%ref%\=!
    set absolutePath=!absolutePath:%rel%\=!
    goto LOOP
)
:RELLOOP
for /F "tokens=1 delims=\" %%a in ("%absolutePath%") do (
    set absolutePath=!absolutePath:%%a\=!
    set relativePath=!relativePath!..\
)
if not "%absolutePath%"=="" goto RELLOOP
set complRelPath=%relativePath%%referencePath%
echo !complRelPath!

如果文件夹位于不同的驱动器上,这将不会为您提供输出,因此您必须自己处理此特殊情况。

编辑(评论):嗯,这不是你自己想不出来的那么难。如果/\是混合的(这是一个坏主意 - 我们在Windows上!Windows意味着\在路径中,UNIX等意味着/在路径中)你应该替换/ by:

SET referencePath=%referencePath:/=\%
SET absolutePath=%absolutePath:/=\%

如果路径相同,则无需执行此操作:

IF %referencePath%==%absolutePath% (
    SET complRelPath=.\
    GOTO WHATEVER
)

答案 1 :(得分:0)

@ECHO OFF
setlocal enabledelayedexpansion
set referencePath=C:\Users\xyz\project\
set absolutePath=C:\Users\xyz\other\somedir\
FOR %%a IN ("%absolutepath%") DO FOR %%r IN ("%referencepath%.") DO (
 SET "abspath=%%~pa"
 SET "relativepath=!abspath:%%~pr=..\!"
)
echo %relativePath%

GOTO :EOF

如果您要告诉我们您想要的输出是什么,将会有所帮助。告诉我们你当前代码的输出是什么,并且隐含地说这不是你所期望的,然后如何使用其他平台获得某些东西并不是特别有帮助。

问题是您正在尝试替换包含冒号的字符串中包含冒号的字符串。 cmd`感到困惑,因为它不知道三者中哪个是哪个冒号。

此解决方案已被重新设置,因为它假定要删除的路径部分恰好是referencepath的父目录。在没有更多信息的情况下,据我准备猜测......

答案 2 :(得分:0)

虽然我完全理解你想做什么,但我不喜欢这种方法。

相反,为什么不使用您的环境路径,我们将在路径中搜索相关文件。

@echo off
for %%g in ("bin\startup-batch.cmd") do @set "pathTobat=%%~$PATH:g"
echo "%pathTobat%"

答案 3 :(得分:0)

...以及利用PowerShell的示例:

@Echo Off
Set "referencePath=C:\Users\xyz\project"
Set "absolutePath=C:\Users\xyz\other\somedir"
Set "relativePath="
Set "_="
If /I Not "%CD%"=="%referencePath%" (Set "_=T"
    PushD "%referencePath%" 2>Nul || Exit /B)
For /F "Delims=" %%A In ('
    PowerShell -C "Resolve-Path -LiteralPath '%absolutePath%' -Relative"
') Do Set "relativePath=%%A"
If Defined _ PopD
If Defined relativePath Echo %relativePath%
Pause

这显然只适用于实际存在的路径

答案 4 :(得分:0)

@MichaelS的解决方案很好,但是有问题:

  • 如果子目录与其父目录具有相同或相似的名称,则该目录不起作用。
  • 没有本地本地设置的setlocal
  • 相同路径条件不在脚本中
  • 没有命令行界面(CLI)

改进后的版本如下:(另存为 AND t2.column4 = .... AND t2.column5 = .... )(您需要https://ss64.com/nt/syntax-strlen.html中的setComRelPath.bat

strlen.cmd

如果您希望它正常运行,请取消注释@echo off rem Usage: call setCompRelPath.bat C:\A\B C:\i\am\here rem echo "%compRelPath%" rem rem Alternernatively, rem set position_target=D:\44_Projekte\imagine\ rem set position_now=%CD%\ rem call setCompRelPath.bat rem echo "%compRelPath%" if not [%1]==[] set position_target=%1 if not [%2]==[] set position_now=%2 set __absolutePath=%position_now% set __referencePath=%position_target% if %__referencePath%==%__absolutePath% ( set complRelPath=.\ exit /b ) rem echo __referencePath=%__referencePath% rem echo __absolutePath=%__absolutePath% set relativePath= :LOOP for /F "tokens=1 delims=\" %%a in ("%__referencePath%") do (set ref=%%a) for /F "tokens=1 delims=\" %%a in ("%__absolutePath%") do (set rel=%%a) if /i not %ref%==%rel% goto RELLOOP call strlen.cmd "x%ref%" _strlen call set __referencePath=%%__referencePath:~%_strlen%%% call set __absolutePath=%%__absolutePath:~%_strlen%%% rem echo abs^> %__absolutePath% goto LOOP :RELLOOP for /F "tokens=1 delims=\" %%a in ("%__absolutePath%") do call :SUB_relpath %%a if not "%__absolutePath%"=="" goto RELLOOP goto FIN :SUB_relpath set ARG=%1 call strlen.cmd "x%ARG%" _strlen rem echo abs: %__absolutePath% // ARG=%ARG% // rel: %relativePath% call set __absolutePath=%%__absolutePath:~%_strlen%%% set relativePath=%relativePath%..\ exit /b :FIN set compRelPath=%relativePath%%__referencePath%

答案 5 :(得分:0)

好吧,通常我强烈建议不要在文件或目录路径上进行字符串操作,因为它很容易失败。但是对于像这样的不依赖现有路径的任务,似乎没有办法解决。

无论如何,为了以可靠的方式进行操作,必须考虑以下问题:

  • Windows使用不区分大小写的路径,因此所有路径比较也都采用这种方式!
  • 避免使用子字符串替换,因为使用=符号和其他一些字符会造成麻烦!
  • 使用~f循环元变量的for修饰符,确保正确解析提供的路径!这样可以确保输入路径是绝对绝对的,它们不包含双倍分隔符(\\),并且不包含带有...的序列(例如abc\..\.\def,等效于def),这使比较变得困难。
  • 请注意,路径可能以丑陋的方式提供,例如尾随\\.,引号不正确(例如abc\"def ghi"\jkl)或使用错误的路径分隔符({{1} },而不是Windows标准的/

好的,让我们转到我写的一个脚本,该脚本针对所有上述项导出两个绝对路径之间的公共路径和相对路径(请参见\注释):

rem

请注意,这种方法不支持UNC路径。