从相对path和/或文件名parsing绝对path
有没有办法在Windows批处理脚本从包含文件名和/或相对path的值返回绝对path?
鉴于:
"..\" "..\somefile.txt"
我需要相对于batch file的绝对path。
例:
- “somefile.txt”位于“C:\ Foo \”
- “test.bat”位于“C:\ Foo \ Bar”中。
- 用户在“C:\ Foo”中打开命令窗口并调用
Bar\test.bat ..\somefile.txt
- 在batch file“C:\ Foo \ somefile.txt”将从
%1
派生
在batch file中,如在标准C程序中一样,参数0包含当前正在执行的脚本的path。 您可以使用%~dp0
来仅获取第0个参数(即当前脚本)的path部分 – 此path始终是完全限定的path。
你也可以通过使用%~f1
来得到第一个参数的全限定path,但是这会给出一个根据当前工作目录的path,这显然不是你想要的。
就我个人而言,我经常在我的batch file中使用%~dp0%~1
习语,它解释了相对于执行批处理path的第一个参数。 但是它有一个缺点:如果第一个参数是完全合格的,它就会失败。
如果您需要支持相对path和绝对path,则可以使用FrédéricMénez的解决scheme :临时更改当前工作目录。
下面是一个将演示这些技术的例子:
@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"
今天早上我遇到了类似的需求:如何在Windows命令脚本中将相对path转换为绝对path。
以下是诀窍:
@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%
大多数这些答案似乎是疯狂的复杂和超级越野车,这是我的 – 它适用于任何环境variables,没有%CD%
或PUSHD
/ POPD
,或for /f
废话 – 只是普通的旧批处理function。 – 目录&文件甚至不必存在。
CALL :NORMALIZEPATH "..\..\..\foo\bar.txt" SET BLAH=%RETVAL% ECHO "%BLAH%" :: ========== FUNCTIONS ========== EXIT /B :NORMALIZEPATH SET RETVAL=%~dpfn1 EXIT /B
不必有另一个batch file传递参数(并使用参数运算符),您可以使用FOR /F
:
FOR /F %%i IN ("..\relativePath") DO echo absolute path: %%~fi
其中%%~fi
中的i
是在/F %%i
处定义的variables。 例如。 如果您将其更改为/F %%a
那么最后一部分将是%%~fa
。
要在命令提示符处(而不是在batch file中)执行相同的操作,请将%%
replace为%
…
这是为了帮助填补Adrien Plisson的答案(在他编辑它时应立即提出); – ):
你也可以通过使用%〜f1来得到你的第一个参数的全限定path,但是这给出了一个根据当前path的path,这显然不是你想要的。
不幸的是,我不知道如何混合在一起…
可以同样处理%0
和%1
:
-
%~dpnx0
为完全合格的驱动器+path+名称+batch file本身的扩展名,
%~f0
也足够了; -
%~dpnx1
完全合格的驱动器+path+名称+扩展名的第一个参数[如果这是一个文件名],
%~f1
也足够了;
%~f1
将独立于指定第一个参数的方式工作:使用相对path或使用绝对path(如果在命名%1
时未指定文件扩展名,则不会添加,即使使用%~dpnx1
– 但是。
但是如果你不在命令行上提供完整的path信息,那么如何在不同的驱动器上命名一个文件呢?
但是,如果你对path(没有驱动器号),文件名(没有扩展名)感兴趣,只有扩展名或文件名扩展名的完整文件名, %~nx0
, %~nx0
, %~nx0
和%~x0
%~nx0
可能会派上用场。 但是请注意, %~p1
和%~n1
将查找第一个参数的path或名称, %~nx1
和%~x1
将不会添加+显示扩展名,除非已经在命令行上使用它。
您也可以使用批处理function:
@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
我还没有看到这个问题的很多解决scheme。 一些解决scheme使用CD的目录遍历,而其他的使用批处理function。 我的个人喜好是批处理function,特别是由DosTips提供的MakeAbsolutefunction。
这个函数有一些真正的好处,主要是它不会改变你当前的工作目录,其次是被评估的path甚至不需要存在。 你也可以在这里find一些关于如何使用这个函数的有用提示。
这是一个脚本及其输出示例:
@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
我希望这有助于…它肯定帮了我:) PS再次感谢DosTips! 你摇滚!
BrainSlugs83的优秀解决scheme略有改进。 通用来允许在调用中命名输出环境variables。
@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
在你的例子中,从Bar \ test.bat,DIR / B / S .. \ somefile.txt将返回完整的path。
你可以连接它们。
SET ABS_PATH=%~dp0 SET REL_PATH=..\SomeFile.txt SET COMBINED_PATH=%ABS_PATH%%REL_PATH%
它在你的path中间看起来很奇怪\ \ \但它的工作原理。 不需要做任何疯狂的事情:)
PowerShell现在很常见,所以我经常使用它作为调用C#的快捷方式,因为它具有几乎所有的function:
@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%
这有点慢,但所获得的function是很难打败的,除非不诉诸于实际的脚本语言。
stijn的解决scheme在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%
文件查看所有其他答案
目录
用..
作为你的相对path,假设你目前在D:\Projects\EditorProject
:
cd .. & cd & cd EditorProject
(相对path)
返回绝对path例如
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