Resolver caminho absoluto de caminho relativo e / ou nome do arquivo
-
22-07-2019 - |
Pergunta
Existe uma maneira em um script de lote do Windows para retornar um caminho absoluto de um valor que contém um nome de arquivo e / ou caminho relativo?
Dada:
"..\"
"..\somefile.txt"
Eu preciso o caminho absoluto em relação ao arquivo de lote.
- "somefile.txt" está localizado em "C: \ Foo \"
- "test.bat" está localizado em "C: \ Foo \ Bar".
- O usuário abre uma janela de comando no "C: \ Foo" e chama
Bar\test.bat ..\somefile.txt
- No arquivo de lote "C: \ Foo \ somefile.txt" seria derivado
%1
Solução
Em arquivos em lote, como em programas em C padrão, o argumento 0 contém o caminho para o script atualmente em execução. Você pode usar %~dp0
para obter apenas a parte do caminho do argumento 0 (que é o script atual.) - este caminho é sempre um caminho totalmente qualificado
Você também pode obter o caminho totalmente qualificado do seu primeiro argumento usando %~f1
, mas isso dá um caminho de acordo com o diretório de trabalho atual, o que obviamente não é o que você quer.
Pessoalmente, costumo usar o idioma %~dp0%~1
no meu arquivo de lote, que interpretam o primeiro argumento relativo ao caminho do lote execução. Ele tem uma lacuna no entanto:. Ele miseravelmente falha se o primeiro argumento é totalmente qualificado
Se você precisa para suportar tanto em relação e caminhos absolutos, você pode fazer uso de Frédéric Ménez solução: alterar temporariamente o diretório de trabalho atual.
Aqui está um exemplo que vai demonstrar cada uma destas técnicas:
@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
Se você salve como c: \ temp \ example.bat e executá-lo de c: \ Users \ Public como
c: \ Users \ Public> \ temp \ example.bat .. \ windows
... você vai observar o seguinte resultado:
%~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"
a documentação para o conjunto de modificadores permitidos em um argumento lote pode ser encontrada aqui: https://docs.microsoft.com/en- us / windows-server / administração / windows-comandos / call
Outras dicas
me deparei com uma necessidade semelhante esta manhã:. Como converter um caminho relativo para um caminho absoluto dentro de um script de comandos do Windows
A seguir fez o truque:
@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%
A maioria destas respostas parecer loucura buggy sobre complicada e super, aqui é meu - ele funciona em qualquer variável de ambiente, não %CD%
ou PUSHD
/ POPD
, ou for /f
absurdo - funções de lotes antigos simplesmente. -. O diretório & arquivo não tem sequer a existir
CALL :NORMALIZEPATH "..\..\..\foo\bar.txt"
SET BLAH=%RETVAL%
ECHO "%BLAH%"
:: ========== FUNCTIONS ==========
EXIT /B
:NORMALIZEPATH
SET RETVAL=%~dpfn1
EXIT /B
Sem ter que ter outro arquivo de lote para passar argumentos para (e usar os operadores de argumentos), você pode usar FOR /F
:
FOR /F %%i IN ("..\relativePath") DO echo absolute path: %%~fi
onde o i
em %%~fi
é a variável definida pelo /F %%i
. por exemplo. se você mudou isso para /F %%a
em seguida, a última parte seria %%~fa
.
Para fazer a mesma coisa certa no prompt de comando (e não em um arquivo de lote) substituir %%
com %
...
Esta é para ajudar a preencher as lacunas na resposta de Adrien Plisson (que deve ser upvoted assim que edita; -):
você também pode obter o caminho totalmente qualificado do seu primeiro argumento, usando% ~ f1, mas isso dá um caminho de acordo com o caminho atual, o que obviamente não é o que você quer.
, infelizmente, eu não sei como misturar os 2 juntos ...
Pode-se lidar com %0
e %1
da mesma forma:
-
%~dpnx0
para totalmente qualificado unidade + caminho + nome + extensão da própria batchfile,
%~f0
também é suficiente; -
%~dpnx1
para totalmente qualificado unidade + caminho + nome + extensão do seu primeiro argumento [se isso é um nome de arquivo em tudo],
%~f1
também é suficiente;
%~f1
irá funcionar independente de como você fez especificar o seu primeiro argumento: com caminhos relativos ou com caminhos absolutos (se você não especificar a extensão do arquivo ao nomear %1
, não vai ser adicionado, mesmo se você usar %~dpnx1
- no entanto.
Mas como na terra você nomear um arquivo em uma unidade diferente de qualquer maneira, se você não daria que a plena informações caminho na linha de comando em primeiro lugar?
No entanto, %~p0
, %~n0
, %~nx0
e %~x0
pode vir a calhar, você deve estar interessado no caminho (sem driveletter), nome do arquivo (sem extensão), nome completo com extensão ou apenas a extensão do nome de arquivo. Mas nota, enquanto %~p1
e %~n1
irá trabalhar para descobrir o caminho ou o nome do primeiro argumento, %~nx1
e %~x1
não vai acrescentar + mostrar a extensão, a menos que você usou na linha de comando já.
Você também pode usar funções de lote para isso:
@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
pequena melhoria para de BrainSlugs83 excelente solução . Generalizada para permitir nomear a variável de ambiente de saída na chamada.
@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
Se correr a partir de saída C:\project
é:
C:\project\doc\build
Eu não vi muitas soluções para este problema. Algumas soluções fazem uso de passagem de diretório usando CD e outros fazem uso de funções de lote. Minha preferência pessoal foi para funções de lote e, em particular, a função MakeAbsolute conforme previsto por DosTips.
A função tem alguns benefícios reais, principalmente que não altere seu diretório de trabalho atual e em segundo lugar que os caminhos sendo avaliada nem sequer têm de existir. Você pode encontrar algumas dicas úteis sobre como usar a função aqui também.
Aqui está um script de exemplo e as suas saídas:
@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
E a saída:
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
Espero que isso ajude ... Com certeza me ajudou :) P. S. Obrigado novamente a DosTips! Você rock!
No seu exemplo, do Bar \ test.bat, DIR / B / S .. \ somefile.txt iria retornar o caminho completo.
Você pode simplesmente concatenar-los.
SET ABS_PATH=%~dp0
SET REL_PATH=..\SomeFile.txt
SET COMBINED_PATH=%ABS_PATH%%REL_PATH%
parece estranho com \ .. \ no meio do seu caminho, mas ele funciona. Não há necessidade de fazer nada louco:)
PowerShell é bastante comum nos dias de hoje para que eu usá-lo muitas vezes como uma maneira rápida para invocar C # desde que tem funções para praticamente tudo:
@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%
É um pouco lento, mas a funcionalidade ganhou é difícil de bater a menos, sem recorrer a uma linguagem de script real.
solução funciona de Stijn com subpastas sob 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%
Arquivos Veja todas as outras respostas
Directories
Com ..
ser seu caminho relativo, e supondo que você está atualmente em D:\Projects\EditorProject
:
cd .. & cd & cd EditorProject
(o caminho relativo)
retorna caminho absoluto por exemplo.
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