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

时间:2009-10-29 18:58:56

标签: windows batch-file relative-path absolute-path

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

假设:

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

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

示例:

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

14 个答案:

答案 0 :(得分:149)

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

您还可以使用%~f1获取第一个参数的完全限定路径,但这会根据当前工作目录提供路径,这显然不是您想要的。

就个人而言,我经常在我的批处理文件中使用%~dp0%~1成语,它解释了相对于执行批处理路径的第一个参数。它确实有一个缺点:如果第一个参数完全合格,它就会失败。

如果您需要同时支持相对绝对路径,则可以使用Frédéric Ménez's solution:临时更改当前工作目录。

这是一个展示这些技巧的例子:

@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运行

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"

答案 1 :(得分:137)

今天早上我遇到了类似的需求:如何将相对路径转换为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%

答案 2 :(得分:73)

这些答案中的大多数似乎都比复杂和超级越野车更疯狂,这是我的 - 它适用于任何环境变量,没有%CD%PUSHD / POPD或{{1}无意义 - 只是普通的旧批处理函数。 - 目录&文件甚至不必存在。

for /f

答案 3 :(得分:35)

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

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

i中的%%~fi/F %%i定义的变量。例如。如果您将其更改为/F %%a,那么最后一部分将为%%~fa

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

答案 4 :(得分:15)

这是为了帮助填补Adrien Plisson答案中的空白(应该在编辑后立即加注; - ):

  

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

     

不幸的是,我不知道如何将2个混合在一起......

同样可以处理%0%1

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

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

但是,如果你不首先在命令行上提供完整的路径信息,那么你究竟如何在不同的驱动器上命名文件

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

答案 5 :(得分:9)

您也可以使用批处理功能:

@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

答案 6 :(得分:6)

BrainSlugs83's excellent solution的小改进。通用以允许在调用中命名输出环境变量。

@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

答案 7 :(得分:4)

我没有看到很多解决这个问题的方法。一些解决方案使用CD来使用目录遍历,而其他解决方案则使用批处理功能。我个人的偏好是批处理功能,特别是DosTips提供的MakeAbsolute功能。

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

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

@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!你摇滚!

答案 8 :(得分:1)

在你的例子中,从Bar \ test.bat,DIR / B / S .. \ somefile.txt将返回完整路径。

答案 9 :(得分:1)

你可以将它们连接起来。

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

在路径中间\ .. \看起来很奇怪但是它有效。不需要做任何疯狂的事情:)

答案 10 :(得分:0)

PowerShell现在非常普遍,所以我经常使用它作为调用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%

它有点慢,但除非不采用实际的脚本语言,否则所获得的功能很难被击败。

答案 11 :(得分:0)

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%

答案 12 :(得分:0)

文件查看所有其他答案

<强>目录

..是您的相对路径,并假设您当前在D:\Projects\EditorProject

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

返回绝对路径,例如

D:\Projects

答案 13 :(得分:0)

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