从相对路径和/或文件名解析绝对路径

在 Windows 批处理脚本中,是否有办法从包含文件名和/或相对路径的值返回绝对路径?

给出:

"..\"
"..\somefile.txt"

我需要相对于批处理文件的绝对路径。

例如:

  • “ somfile.txt”位于“ C: Foo”
  • “ test.bat”位于“ C: Foo Bar”中。
  • 用户在“ C: Foo”中打开一个命令窗口并调用 Bar\test.bat ..\somefile.txt
  • 在批处理文件中,“ C: Foo somfile.txt”将从 %1派生
268720 次浏览

在您的示例中,从 Bar test.bat,DIR/B/S. . somfile.txt 将返回完整的路径。

在批处理文件中,与标准 C 程序一样,参数0包含当前正在执行的脚本的路径。您可以使用 %~dp0来获取第0个参数的路径部分(即当前脚本)-这个路径始终是一个完全限定的路径。

你也可以通过使用 %~f1得到第一个参数的完全限定路径,但是这会根据当前的工作目录给出一个路径,这显然不是你想要的。

就个人而言,我经常在批处理文件中使用 %~dp0%~1习惯用法,它解释与正在执行的批处理的路径相关的第一个参数。但它也有一个缺点: 如果第一个参数是完全限定的,那么它就很可悲地失败了。

如果你需要同时支持相对的 还有绝对路径,你可以利用 弗雷德里克 · 梅内斯的解决方案: 临时改变当前的工作目录。

下面的例子将演示这些技术中的每一种:

@echo off
echo %%~dp0 is "%~dp0"
echo %%0 is "%0"
echo %%~dpnx0 is "%~dpnx0"
echo %%~f1 is "%~f1"
echo %%~dp0%%~1 is "%~dp0%~1"


rem Temporarily change the current working directory, to retrieve a full path
rem   to the first parameter
pushd .
cd %~dp0
echo batch-relative %%~f1 is "%~f1"
popd

如果您将其保存为 c: temp example.bat,并从 c: Users Public as 运行它

C: Users Public > temp example.bat. . windows

你会看到以下输出:

%~dp0 is "C:\temp\"
%0 is "\temp\example.bat"
%~dpnx0 is "C:\temp\example.bat"
%~f1 is "C:\Users\windows"
%~dp0%~1 is "C:\temp\..\windows"
batch-relative %~f1 is "C:\Windows"

关于批处理参数允许的修饰符集的文档可以在这里找到: Https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/call

这有助于填补阿德里安•普利松(Adrien Plisson)回答中的空白(他一编辑这个问题,就应该对其进行表决) :

您还可以使用% ~ f1获得第一个参数的完全限定路径,但是这会根据当前路径给出一个路径,显然这不是您想要的。

不幸的是,我不知道怎么把两者混合在一起。

同样,我们也可以处理 %0%1:

  • %~dpnx0用于完全限定的驱动器 + 路径 + 名称 + 批处理文件本身的扩展名,
    %~f0也足够了;
  • %~dpnx1用于完全限定的驱动器 + 路径 + 名称 + 其第一个参数的扩展名[如果这是一个文件名] ,
    %~f1也足够了;

%~f1将独立于您指定第一个参数的方式: 使用相对路径或绝对路径(如果在命名 %1时没有指定文件的扩展名,那么它将不会被添加,即使您使用 %~dpnx1——但是。

但是如果一开始不在命令行上提供完整的路径信息,那么到底怎样才能将文件命名为 在另一个硬盘上呢?

然而,%~p0%~n0%~nx0%~x0可能会派上用场,如果你感兴趣的路径(没有驱动器) ,文件名(没有扩展名) ,完整的文件名与扩展名或文件名的扩展名只。但是请注意,虽然 %~p1%~n1将查找第一个参数的路径或名称,但是 %~nx1%~x1不会添加 + 显示扩展名,除非您已经在命令行中使用了它。

今天早上我遇到了一个类似的需求: 如何在 Windows 命令脚本中将相对路径转换为绝对路径。

下面的方法奏效了:

@echo off


set REL_PATH=..\..\
set ABS_PATH=


rem // Save current directory and change to target directory
pushd %REL_PATH%


rem // Save value of CD variable (current directory)
set ABS_PATH=%CD%


rem // Restore original directory
popd


echo Relative path: %REL_PATH%
echo Maps to path: %ABS_PATH%

还可以使用批处理函数:

@echo off
setlocal


goto MAIN
::-----------------------------------------------
:: "%~f2" get abs path of %~2.
::"%~fs2" get abs path with short names of %~2.
:setAbsPath
setlocal
set __absPath=%~f2
endlocal && set %1=%__absPath%
goto :eof
::-----------------------------------------------


:MAIN
call :setAbsPath ABS_PATH ..\
echo %ABS_PATH%


endlocal

我没有看到很多解决这个问题的办法。一些解决方案使用 CD 进行目录遍历,另一些解决方案使用批处理函数。我个人偏爱批处理功能,特别是 DosTips 提供的 MakeAbsolute功能。

这个函数有一些实际的好处,主要是它不会改变你当前的工作目录,其次是被评估的路径甚至不需要存在。您还可以找到一些关于如何使用函数 给你的有用提示。

下面是一个示例脚本及其输出:

@echo off


set scriptpath=%~dp0
set siblingfile=sibling.bat
set siblingfolder=sibling\
set fnwsfolder=folder name with spaces\
set descendantfolder=sibling\descendant\
set ancestorfolder=..\..\
set cousinfolder=..\uncle\cousin


call:MakeAbsolute siblingfile      "%scriptpath%"
call:MakeAbsolute siblingfolder    "%scriptpath%"
call:MakeAbsolute fnwsfolder       "%scriptpath%"
call:MakeAbsolute descendantfolder "%scriptpath%"
call:MakeAbsolute ancestorfolder   "%scriptpath%"
call:MakeAbsolute cousinfolder     "%scriptpath%"


echo scriptpath:       %scriptpath%
echo siblingfile:      %siblingfile%
echo siblingfolder:    %siblingfolder%
echo fnwsfolder:       %fnwsfolder%
echo descendantfolder: %descendantfolder%
echo ancestorfolder:   %ancestorfolder%
echo cousinfolder:     %cousinfolder%
GOTO:EOF


::----------------------------------------------------------------------------------
:: Function declarations
:: Handy to read http://www.dostips.com/DtTutoFunctions.php for how dos functions
:: work.
::----------------------------------------------------------------------------------
:MakeAbsolute file base -- makes a file name absolute considering a base path
::                      -- file [in,out] - variable with file name to be converted, or file name itself for result in stdout
::                      -- base [in,opt] - base path, leave blank for current directory
:$created 20060101 :$changed 20080219 :$categories Path
:$source http://www.dostips.com
SETLOCAL ENABLEDELAYEDEXPANSION
set "src=%~1"
if defined %1 set "src=!%~1!"
set "bas=%~2"
if not defined bas set "bas=%cd%"
for /f "tokens=*" %%a in ("%bas%.\%src%") do set "src=%%~fa"
( ENDLOCAL & REM RETURN VALUES
IF defined %1 (SET %~1=%src%) ELSE ECHO.%src%
)
EXIT /b

结果是:

C:\Users\dayneo\Documents>myscript
scriptpath:       C:\Users\dayneo\Documents\
siblingfile:      C:\Users\dayneo\Documents\sibling.bat
siblingfolder:    C:\Users\dayneo\Documents\sibling\
fnwsfolder:       C:\Users\dayneo\Documents\folder name with spaces\
descendantfolder: C:\Users\dayneo\Documents\sibling\descendant\
ancestorfolder:   C:\Users\
cousinfolder:     C:\Users\dayneo\uncle\cousin

我希望这有帮助... ... 它确实帮助了我:) 附注: 再次感谢 DosTips! 你太棒了!

不需要另一个批处理文件来传递参数(并使用参数运算符) ,您可以使用 FOR /F:

FOR /F %%i IN ("..\relativePath") DO echo absolute path: %%~fi

其中 %%~fi中的 i是在 /F %%i中定义的变量。如果你把它改成 /F %%a,那么最后一部分就是 %%~fa

要在命令提示符下(而不是在批处理文件中)执行同样的操作,请将 %%替换为 %..。

你可以把它们连接起来。

SET ABS_PATH=%~dp0
SET REL_PATH=..\SomeFile.txt
SET COMBINED_PATH=%ABS_PATH%%REL_PATH%

看起来很奇怪。.在你的道路中间,但它的工作。不需要做任何疯狂的事情:)

PowerShell 现在已经很常见了,所以我经常用它来快速调用 C # ,因为 C # 几乎包含了所有的函数:

@echo off
set pathToResolve=%~dp0\..\SomeFile.txt
for /f "delims=" %%a in ('powershell -Command "[System.IO.Path]::GetFullPath( '%projectDirMc%' )"') do @set resolvedPath=%%a


echo Resolved path: %resolvedPath%

虽然有点慢,但是获得的功能是很难打败的,除非不依靠实际的脚本语言。

Stijn 的解决方案使用 C:\Program Files (86)\下的子文件夹,

@echo off
set projectDirMc=test.txt


for /f "delims=" %%a in ('powershell -Command "[System.IO.Path]::GetFullPath( '%projectDirMc%' )"') do @set resolvedPath=%%a


echo full path:    %resolvedPath%

文件 查看所有其他答案

目录

..作为你的相对路径,假设你现在在 D:\Projects\EditorProject:

cd .. & cd & cd EditorProject(相对路径)

返回绝对路径。

D:\Projects

SET CD=%~DP0


SET REL_PATH=%CD%..\..\build\


call :ABSOLUTE_PATH    ABS_PATH   %REL_PATH%


ECHO %REL_PATH%


ECHO %ABS_PATH%


pause


exit /b


:ABSOLUTE_PATH


SET %1=%~f2


exit /b

这些答案中的大多数似乎疯狂的复杂和超级错误,这里是我的-它的工作在任何环境变量,没有 %CD%PUSHD/POPD,或 for /f废话-只是普通的老批处理功能。——目录 & 文件甚至不必存在。

CALL :NORMALIZEPATH "..\..\..\foo\bar.txt"
SET BLAH=%RETVAL%


ECHO "%BLAH%"


:: ========== FUNCTIONS ==========
EXIT /B


:NORMALIZEPATH
SET RETVAL=%~f1
EXIT /B

BrainSlugs83的绝佳解决方案的小改进。通用化,允许在调用中命名输出环境变量。

@echo off
setlocal EnableDelayedExpansion


rem Example input value.
set RelativePath=doc\build


rem Resolve path.
call :ResolvePath AbsolutePath %RelativePath%


rem Output result.
echo %AbsolutePath%


rem End.
exit /b


rem === Functions ===


rem Resolve path to absolute.
rem Param 1: Name of output variable.
rem Param 2: Path to resolve.
rem Return: Resolved absolute path.
:ResolvePath
set %1=%~dpfn2
exit /b

如果从 C:\project输出运行为:

C:\project\doc\build