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.

Exemplo:

  • "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
Foi útil?

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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top