Разрешить абсолютный путь из относительного пути и/или имени файла
есть ли способ в пакетном скрипте Windows вернуть абсолютный путь из значения, содержащего имя файла и / или относительный путь?
дано:
".."
"..somefile.txt"
мне нужен абсолютный путь к пакетному файлу.
пример:
- " какой-то файл.txt " находится в "C:Foo"
- "тест.летучая мышь " находится в "C:FooBar".
- пользователь открывает окно команд в "C:Foo" и звонит
Bartest.bat ..somefile.txt
- в пакетном файле "C:Foosomefile.тхт" могут быть получены с помощью
%1
14 ответов:
в пакетных файлах, как и в стандартных программах на языке 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.летучая мышь и беги от нее c:\Users\Public как
c:\Users\Public> \ temp\пример.летучая мышь..\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.
следующий трюк:
@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.сделать то же самое прямо в командной строке (а не в пакетном файле) заменить
%%С%...
это поможет заполнить пробелы в ответе Адриена Плиссона (который должен быть повышен, как только он его редактирует; -):
вы также можете получить полный путь вашего первого аргумента с помощью %~f1, но это дает путь в соответствии с текущим путем, который, очевидно, не то, что вы хотите.
к сожалению, я не знаю, как смешать 2 вместе...
можно обрабатывать
%0и%1дополнительно:
%~dpnx0для полного диска + путь+имя+расширение самого файла пакета,%~f0тоже хватает;%~dpnx1для полного диска + путь+имя + расширение его первого аргумента [если это имя файла вообще],%~f1тоже хватает;
%~f1будет работать независимо от того, как вы указали ваш первый аргумент: с относительными путями или с абсолютными путями (если вы не укажите расширение файла при именовании%1, он не будет добавлен, даже если вы используете%~dpnx1-- однако.но как бы вы назвали файл на другом диске в любом случае, если бы вы не дали эту полную информацию о пути в командной строке в первую очередь?
,%~p0,%~n0,%~nx0и%~x0может пригодиться, если вас интересует путь (без driveletter), имя файла (без расширения), полное имя файла с расширением или только расширение имени файла. Но заметьте, пока%~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
Я не видел много решений этой проблемы. Некоторые решения используют обход каталога с помощью CD, а другие используют пакетные функции. Мое личное предпочтение было для пакетных функций и, в частности, 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и вывод:
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! Ты крут!
небольшое улучшение 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
вы можете просто объединить их.
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
Comments