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

鉴于:

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

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

例子:

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

解决方案

在批处理文件中,与标准 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: emp\example.bat 并从 c:\Users\Public 运行它

c:\Users\Public> emp\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://docs.microsoft.com/en-us/windows-server/administration/windows-commands/call

其他提示

今天早上我也遇到了类似的需求:如何在 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%

这些答案中的大多数看起来都过于复杂和超级错误,这是我的——它适用于任何环境变量,不 %CD% 或者 PUSHD/POPD, , 或者 for /f 废话——只是普通的旧批处理函数。-- 目录和文件甚至不必存在。

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

ECHO "%BLAH%"

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

:NORMALIZEPATH
  SET RETVAL=%~dpfn1
  EXIT /B

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

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

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

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

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

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

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

一个人就能搞定 %0%1 同样地:

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

%~f1 将独立于您如何指定第一个参数而工作:使用相对路径或绝对路径(如果命名时未指定文件扩展名) %1, ,即使您使用,也不会添加 %~dpnx1 - 然而。

但是你到底如何命名一个文件 在不同的驱动器上 无论如何,如果您一开始就不在命令行上提供完整的路径信息?

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

您还可以使用批处理函数来执行此操作:

@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的优秀解决方案. 。通用化以允许在调用中命名输出环境变量。

@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

我还没有看到这个问题的很多解决方案。一些解决方案利用 CD 进行目录遍历,而其他解决方案则利用批处理功能。我个人更喜欢批处理功能,特别是 绝对制作 DosTips 提供的功能。

该函数有一些真正的好处,首先它不会更改您当前的工作目录,其次正在评估的路径甚至不必存在。您可以找到一些有关如何使用该功能的有用提示 这里 也。

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

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

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

您可以将它们连接起来。

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

路径中间的 \..\ 看起来很奇怪,但它可以工作。没必要做任何疯狂的事情:)

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%

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

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
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top