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

Nat*_*lor 147 windows batch-file relative-path absolute-path

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

鉴于:

"..\"
"..\somefile.txt"
Run Code Online (Sandbox Code Playgroud)

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

例:

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

Adr*_*son 155

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

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

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

如果您需要支持相对路径绝对路径,您可以使用FrédéricMénez的解决方案:临时更改当前工作目录.

这是一个展示每种技术的例子:

@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
Run Code Online (Sandbox Code Playgroud)

如果将其保存为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"
Run Code Online (Sandbox Code Playgroud)

  • 您可以同样处理`%0`和`%1`:`%〜dpnx0`用于完全限定的路径+批处理文件本身的名称,`%~dpnx1`用于完全限定的路径+其第一个参数的名称[如果这是文件名在所有].(但是,如果你不打算在命令行上提供完整的路径信息,你怎么能在不同的驱动器上命名文件?) (4认同)
  • 这在NTFS符号链接上失败. (3认同)

小智 142

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

  • 不要认为有必要让"推"后跟"cd".你可以做"pushd%REL_PATH%".这将保存当前目录并一次切换到REL_PATH. (7认同)
  • @EddieSullivan如果更改到目录失败(目录不存在,没有权限...),pushd命令也会失败,并且实际上不会将值推送到目录堆栈.popd的下一个调用(以及所有连续调用)将弹出错误的值.使用`pushd .`可以防止出现此问题. (6认同)
  • 这非常有用.有没有这样的批处理文件技巧的好资源? (2认同)
  • 请注意,这不适用于文件路径或中间有 .. 的不存在路径。这对我来说并不是一个阻碍,但它是可重用解决方案的一个弱点。 (2认同)

Bra*_*s83 85

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

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

ECHO "%BLAH%"

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

:NORMALIZEPATH
  SET RETVAL=%~dpfn1
  EXIT /B
Run Code Online (Sandbox Code Playgroud)

  • 这确实是一个干净,有效和直接的解决方案. (6认同)
  • 简单,干净,可读.非常感谢你! (5认同)
  • 非常简洁。我现在正在广泛使用这种技术。 (3认同)
  • @il--ya 看起来 `%~f1` 只是 `%~dpfn1` 的缩写 - 所以,请随意使用 `%~f1` 来代替。-- 在长格式中,“~”表示删除引号,“d”表示驱动器,“p”表示路径,“n”单独表示不带扩展名的文件名,但“fn”表示带扩展名的文件名。‘1’ 表示第一个参数。--(我相信这种格式早于 Windows 7。) (3认同)
  • 啊,你抢先了我!根据 nt4 源代码中的注释,文件 nt4\private\windows\cmd\clex.c (日期为 27/08/1997),函数 MSCmdVar(), "// %~fi - 将 %i 扩展为完全限定路径名字“抱歉打扰你了。我希望我能弄清楚这个误解的真相。我在审查一些最近的代码时遇到了 %~dpfn,我费了好大劲试图理解它应该做什么(请注意,我已经没有多少头发了),并开始调查它是如何诞生的:个人恩怨。 (3认同)

Pet*_*hie 35

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

FOR /F %%i IN ("..\relativePath") DO echo absolute path: %%~fi
Run Code Online (Sandbox Code Playgroud)

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

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

  • ```FOR /F %%i IN ("..\relativePath") DO echo absolute path: %%~fi``` 将失败,如果 ```..\relativePath``` 包含空格 (2认同)

Kur*_*fle 15

这是为了帮助填补Adrien Plisson答案中的空白(一旦编辑就应该加注;-):

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

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

一个可以处理%0%1同样:

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

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

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

然而%~p0,%~n0,%~nx0并且%~x0可以派上用场了,你应该关心路径(无驱动器号),文件名(不含扩展名),文件全名以扩展或只有文件扩展名.但请注意,虽然%~p1并且%~n1将会找到第一个参数的路径或名称,%~nx1并且%~x1不会添加+显示扩展名,除非您已经在命令行上使用它.


Axe*_*der 10

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

@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
Run Code Online (Sandbox Code Playgroud)


Lyc*_*can 8

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
Run Code Online (Sandbox Code Playgroud)

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

C:\project\doc\build
Run Code Online (Sandbox Code Playgroud)


day*_*neo 5

我还没有看到这个问题的很多解决方案。一些解决方案利用 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
Run Code Online (Sandbox Code Playgroud)

和输出:

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
Run Code Online (Sandbox Code Playgroud)

我希望这会有所帮助...它确实对我有所帮助:) PS 再次感谢 DosTips!你摇滚!