Resolve absolute path from relative path and/or file name
Windows批处理脚本中是否有方法从包含文件名和/或相对路径的值返回绝对路径?
鉴于:
1 2 | ".." "..\somefile.txt" |
我需要相对于批处理文件的绝对路径。
例子:
- "somefile.txt"位于"c:foo"
- "test.bat"位于"c:fooar"中。
- 用户在"c:foo"中打开命令窗口,调用
Bar\test.bat ..\somefile.txt 。 - 批处理文件"c:foosomefile.txt"将从
%1 派生。
在批处理文件中,与标准C程序一样,参数0包含当前执行脚本的路径。您可以使用
您也可以通过使用
就个人而言,我经常在批处理文件中使用
如果需要同时支持相对路径和绝对路径,可以使用fr_d_ric m_nez的解决方案:临时更改当前工作目录。
下面是一个例子,将演示这些技术:
1 2 3 4 5 6 7 8 9 10 11 12 13 | @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: empexample.bat,并从c:userspublic运行为
C:userspublic> empexample.bat..windows
…您将看到以下输出:
1 2 3 4 5 6 | %~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" |
今天早上我遇到了一个类似的需求:如何在Windows命令脚本中将相对路径转换为绝对路径。
以下是技巧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @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% |
这些答案中的大多数似乎都是对复杂和超小型车的疯狂,这里是我的——它适用于任何环境变量,没有
1 2 3 4 5 6 7 8 9 10 11 | CALL :NORMALIZEPATH"..\..\..\foo\bar.txt" SET BLAH=%RETVAL% ECHO"%BLAH%" :: ========== FUNCTIONS ========== EXIT /B :NORMALIZEPATH SET RETVAL=%~dpfn1 EXIT /B |
不需要另一个批处理文件来传递参数(并使用参数运算符),您可以使用
1 2 | FOR /F %%i IN (".. elativePath") DO echo absolute path: %%~fi |
其中
为了在命令提示下(而不是批处理文件中)正确地执行相同的操作,将
这有助于填补阿德里安·普里松(Adrien Plisson)答案中的空白(在他编辑答案后应立即进行上票);—:
you can also get the fully qualified path of your first argument by using %~f1, but this gives a path according to the current path, which is obviously not what you want.
unfortunately, i don't know how to mix the 2 together...
可以同样处理
%~dpnx0 用于完全限定的驱动器+路径+名称+批处理文件本身的扩展名,%~f0 也足够了;%~dpnx1 ,用于完全限定的驱动器+路径+名称+第一个参数的扩展名[如果这是文件名],%~f1 也足够了;
但是,如果你一开始不在命令行上提供完整的路径信息,你到底会如何在不同的驱动器上命名一个文件呢?
但是,如果您对路径(不带驱动器号)、文件名(不带扩展名)、带扩展名的完整文件名或文件名的扩展名感兴趣,那么
您还可以使用批处理函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | @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 |
对Brainslugs83优秀解决方案的小改进。通用化以允许在调用中命名输出环境变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | @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 |
如果从
1 | C:\project\doc\build |
我没有看到很多解决这个问题的方法。一些解决方案使用CD进行目录遍历,另一些解决方案使用批处理函数。我个人倾向于批处理功能,特别是dostips提供的makeabsolute功能。
该函数有一些真正的好处,主要是它不会改变当前的工作目录,其次是被评估的路径甚至不必存在。您也可以在这里找到一些关于如何使用函数的有用提示。
下面是一个示例脚本及其输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | @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 |
输出:
1 2 3 4 5 6 7 8 | 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!你摇滚!
您可以将它们连接起来。
1 2 3 | SET ABS_PATH=%~dp0 SET REL_PATH=..\SomeFile.txt SET COMBINED_PATH=%ABS_PATH%%REL_PATH% |
在你的道路中间有..看起来很奇怪,但它起作用了。不需要做任何疯狂的事情:)
在您的示例中,从bar est.bat,dir/b/s..somefile.txt将返回完整路径。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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 |
文件查看所有其他答案
名录
由于
返回绝对路径,例如
Stijn的解决方案与
1 2 3 4 5 6 | @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% |
PowerShell现在很常见,所以我经常使用它作为一种快速调用C的方法,因为它具有几乎所有功能:
1 2 3 4 5 | @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% |
虽然速度有点慢,但除非不使用实际的脚本语言,否则很难击败所获得的功能。