Разрешить абсолютный путь от относительного пути и/или имени файла

Есть ли способ в пакете Windows script вернуть абсолютный путь из значения, содержащего имя файла и/или относительный путь?

Дано:

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

Мне нужен абсолютный путь относительно командного файла.

Пример:

  • "somefile.txt" находится в папке "C:\Foo \"
  • "test.bat" находится в "C:\Foo\Bar".
  • Пользователь открывает окно команд в "C:\Foo" и вызывает Bar\test.bat ..\somefile.txt
  • В пакетном файле "C:\Foo\somefile.txt" будет выведено из %1

Ответ 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:\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://docs.microsoft.com/en-us/windows-server/administration/windows-commands/call

Ответ 2

Сегодня утром я столкнулся с подобной потребностью: как преобразовать относительный путь в абсолютный путь внутри команды Windows script.

Следующий трюк:

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

Ответ 3

Большинство из этих ответов кажутся сумасшедшими по сравнению с сложной и супер-глючной ошибкой, здесь моя - она ​​работает с любой переменной окружения, без %CD% или PUSHD/POPD, или for /f ерунда - просто старая партия функции. - Каталог и файл даже не должны существовать.

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

ECHO "%BLAH%"

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

:NORMALIZEPATH
  SET RETVAL=%~dpfn1
  EXIT /B

Ответ 4

Без необходимости иметь другой пакетный файл для передачи аргументов (и использования операторов аргументов), вы можете использовать FOR /F:

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

где i in %%~fi - это переменная, определенная в /F %%i. например. если вы изменили это на /F %%a, тогда последняя часть будет %%~fa.

Чтобы сделать то же самое прямо в командной строке (а не в пакетном файле), замените %% на %...

Ответ 5

Это поможет заполнить пробелы в ответе Адриена Плиссона (который должен быть сохранен, как только он его редактирует;):

вы также можете получить полный путь к первому аргументу, используя% ~ f1, но это дает путь в соответствии с текущим путем, что явно не то, что вы хотите.

К сожалению, я не знаю, как смешивать 2 вместе...

Можно обрабатывать %0 и %1 аналогично:

  • %~dpnx0 для полноприводного диска + путь + имя + расширение самого файла пакета,
    %~f0 также достаточно:
  • %~dpnx1 для полностью квалифицированного диска + путь + имя + расширение его первого аргумента [если это имя файла вообще],
    %~f1 также достаточно;

%~f1 будет работать независимо от того, как вы определили свой первый аргумент: с относительными путями или с абсолютными путями (если вы не укажете расширение файла при именовании %1, оно не будет добавлено, даже если вы используйте %~dpnx1 - однако.

Но как бы вы назвали файл на другом диске в любом случае, если бы вы не указали эту полную информацию о пути в командной строке?

Однако %~p0, %~n0, %~nx0 и %~x0 могут пригодиться, если вас интересует путь (без диска), имя файла (без расширения), полное имя файла с расширением или расширением имени файла, Но учтите, что в то время как %~p1 и %~n1 будут работать, чтобы узнать путь или имя первого аргумента, %~nx1 и %~x1 не будут добавлять + показать расширение, если вы уже не использовали его в командной строке.

Ответ 6

Для этого также можно использовать пакетные функции:

@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

Ответ 7

Небольшое улучшение отличное решение 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

Ответ 8

Я не видел много решений этой проблемы. Некоторые решения используют обход каталога, используя CD, а другие используют пакетные функции. Мои личные предпочтения были для пакетных функций и, в частности, MakeAbsolute, как это предусмотрено DosTips.

Функция имеет некоторые реальные преимущества, в первую очередь, что она не изменяет ваш текущий рабочий каталог, а во-вторых, что пути, которые оцениваются, даже не должны существовать. Вы можете найти полезные советы о том, как использовать функцию здесь.

Вот пример script и его выходы:

@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

Надеюсь, это поможет... Это помогло мне:) Постскриптум Еще раз спасибо DosTips! Ты качаешься!

Ответ 9

В вашем примере из Bar\test.bat DIR/B/S..\somefile.txt вернет полный путь.

Ответ 10

Вы можете просто конкатенировать их.

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

он выглядит нечетным с \..\в середине вашего пути, но он работает. Не нужно ничего сумасшедшего:)

Ответ 11

PowerShell довольно распространен в наши дни, поэтому я часто использую его как быстрый способ вызвать С#, поскольку у него есть функции для почти всего:

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

Это немного медленнее, но полученную функциональность трудно превзойти, если не прибегать к реальному языку сценариев.

Ответ 12

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%

Ответ 13

Файлы См. все другие ответы

Каталоги

Если .. является вашим относительным путем и предположим, что вы находитесь в D:\Projects\EditorProject:

cd .. & cd & cd EditorProject (относительный путь)

возвращает абсолютный путь, например.

D:\Projects

Ответ 14

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