상대 경로 및/또는 파일 이름에서 절대 경로를 확인합니다.
-
22-07-2019 - |
문제
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
배치 파일의 관용구는 실행 배치 경로에 대한 첫 번째 인수를 해석합니다. 그래도 단점이 있습니다. 첫 번째 논쟁이 완전히 자격이되면 비참하게 실패합니다.
둘 다 친척을 지원 해야하는 경우 그리고 절대 경로, 당신은 사용할 수 있습니다 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 as에서 실행하면
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-eserver/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를 사용하여 디렉토리 트래버스를 사용하고 다른 솔루션은 배치 기능을 사용합니다. 저의 개인적인 취향은 배치 기능, 특히 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에게 다시 한 번 감사드립니다! 당신은 바위!
예에서, bar test.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