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

发布于 2024-08-09 13:25:54 字数 405 浏览 14 评论 0原文

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

给定:

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

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

示例:

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

Is there a way in a Windows batch script to return an absolute path from a value containing a filename and/or relative path?

Given:

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

I need the absolute path relative to the batch file.

Example:

  • "somefile.txt" is located in "C:\Foo\"
  • "test.bat" is located in "C:\Foo\Bar".
  • User opens a command window in "C:\Foo" and calls Bar\test.bat ..\somefile.txt
  • In the batch file "C:\Foo\somefile.txt" would be derived from %1

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

三月梨花 2024-08-16 13:25:55

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

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

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

可以同样处理%0%1

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

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

如果您不这样做,您到底如何在不同的驱动器上命名文件呢?首先,不要在命令行上提供完整的路径信息,

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

This is to help fill in the gaps in Adrien Plisson's answer (which should be upvoted as soon as he edits it ;-):

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...

One can handle %0 and %1 likewise:

  • %~dpnx0 for fully qualified drive+path+name+extension of the batchfile itself,
    %~f0 also suffices;
  • %~dpnx1 for fully qualified drive+path+name+extension of its first argument [if that's a filename at all],
    %~f1 also suffices;

%~f1 will work independent of how you did specify your first argument: with relative paths or with absolute paths (if you don't specify the file's extension when naming %1, it will not be added, even if you use %~dpnx1 -- however.

But how on earth would you name a file on a different drive anyway if you wouldn't give that full path info on the commandline in the first place?

However, %~p0, %~n0, %~nx0 and %~x0 may come in handy, should you be interested in path (without driveletter), filename (without extension), full filename with extension or filename's extension only. But note, while %~p1 and %~n1 will work to find out the path or name of the first argument, %~nx1 and %~x1 will not add+show the extension, unless you used it on the commandline already.

万人眼中万个我 2024-08-16 13:25:55

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

@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

You can also use batch functions for this:

@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
七色彩虹 2024-08-16 13:25:55

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

Small improvement to BrainSlugs83's excellent solution. Generalized to allow naming the output environment variable in the call.

@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

If run from C:\project output is:

C:\project\doc\build
彩扇题诗 2024-08-16 13:25:55

我还没有看到这个问题的很多解决方案。一些解决方案利用 CD 进行目录遍历,而其他解决方案则利用批处理功能。我个人更喜欢批处理函数,特别是 MakeAbsolute 函数由 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!你摇滚!

I have not seen many solutions to this problem. Some solutions make use of directory traversal using CD and others make use of batch functions. My personal preference has been for batch functions and in particular, the MakeAbsolute function as provided by DosTips.

The function has some real benefits, primarily that it does not change your current working directory and secondly that the paths being evaluated don't even have to exist. You can find some helpful tips on how to use the function here too.

Here is an example script and its outputs:

@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

And the output:

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

I hope this helps... It sure helped me :)
P.S. Thanks again to DosTips! You rock!

说谎友 2024-08-16 13:25:55

您可以将它们连接起来。

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

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

You can just concatenate them.

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

it looks odd with \..\ in the middle of your path but it works. No need to do anything crazy :)

浅忆流年 2024-08-16 13:25:55

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

In your example, from Bar\test.bat, DIR /B /S ..\somefile.txt would return the full path.

左秋 2024-08-16 13:25:55

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%

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

PowerShell is pretty common these days so I use it often as a quick way to invoke C# since that has functions for pretty much everything:

@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%

It's a bit slow, but the functionality gained is hard to beat unless without resorting to an actual scripting language.

木落 2024-08-16 13:25:55

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%

stijn's solution works with subfolders under 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%
画离情绘悲伤 2024-08-16 13:25:55

文件 查看所有其他答案

目录

其中 .. 是您的相对路径,并假设您当前位于 D:\Projects\EditorProject:

cd .. &光盘与cd EditorProject (相对路径)

返回绝对路径,例如

D:\Projects

Files See all other answers

Directories

With .. being your relative path, and assuming you are currently in D:\Projects\EditorProject:

cd .. & cd & cd EditorProject (the relative path)

returns absolute path e.g.

D:\Projects

囚你心 2024-08-16 13:25:55
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
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
回眸一遍 2024-08-16 13:25:54

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

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

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

如果您需要支持相对绝对路径,可以使用Frédéric Mé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

如果将其保存为 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"

可以在此处找到批处理参数上允许的修饰符集的文档:
https://learn.microsoft.com/en-us /windows-server/administration/windows-commands/call

In batch files, as in standard C programs, argument 0 contains the path to the currently executing script. You can use %~dp0 to get only the path portion of the 0th argument (which is the current script) - this path is always a fully qualified path.

You can also get the fully qualified path of your first argument by using %~f1, but this gives a path according to the current working directory, which is obviously not what you want.

Personally, I often use the %~dp0%~1 idiom in my batch file, which interpret the first argument relative to the path of the executing batch. It does have a shortcoming though: it miserably fails if the first argument is fully-qualified.

If you need to support both relative and absolute paths, you can make use of Frédéric Ménez's solution: temporarily change the current working directory.

Here's an example that'll demonstrate each of these techniques:

@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

If you save this as c:\temp\example.bat and the run it from c:\Users\Public as

c:\Users\Public>\temp\example.bat ..\windows

...you'll observe the following output:

%~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"

the documentation for the set of modifiers allowed on a batch argument can be found here:
https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/call

孤檠 2024-08-16 13:25:54

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

I came across a similar need this morning: how to convert a relative path into an absolute path inside a Windows command script.

The following did the trick:

@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%
梦途 2024-08-16 13:25:54

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

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

ECHO "%BLAH%"

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

:NORMALIZEPATH
  SET RETVAL=%~f1
  EXIT /B

Most of these answers seem crazy over complicated and super buggy, here's mine -- it works on any environment variable, no %CD% or PUSHD/POPD, or for /f nonsense -- just plain old batch functions. -- The directory & file don't even have to exist.

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

ECHO "%BLAH%"

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

:NORMALIZEPATH
  SET RETVAL=%~f1
  EXIT /B
顾忌 2024-08-16 13:25:54

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

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

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

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

Without having to have another batch file to pass arguments to (and use the argument operators), you can use FOR /F:

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

where the i in %%~fi is the variable defined at /F %%i. eg. if you changed that to /F %%a then the last part would be %%~fa.

To do the same thing right at the command prompt (and not in a batch file) replace %% with %...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文