Domanda

Esiste un modo in uno script batch di Windows per restituire un percorso assoluto da un valore contenente un nome file e / o percorso relativo?

Data:

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

Ho bisogno del percorso assoluto relativo al file batch.

Esempio:

  • " somefile.txt " si trova in " C: \ Foo \ "
  • " test.bat " si trova in " C: \ Foo \ Bar " ;.
  • L'utente apre una finestra di comando in " C: \ Foo " e chiama Bar \ test.bat .. \ somefile.txt
  • Nel file batch " C: \ Foo \ somefile.txt " sarebbe derivato da %1
È stato utile?

Soluzione

Nei file batch, come nei programmi C standard, l'argomento 0 contiene il percorso dello script attualmente in esecuzione. Puoi usare % ~ dp0 per ottenere solo la parte del percorso del 0 ° argomento (che è lo script corrente) - questo percorso è sempre un percorso completo.

Puoi anche ottenere il percorso completo del tuo primo argomento usando % ~ f1 , ma questo fornisce un percorso secondo l'attuale directory di lavoro, che ovviamente non è quello che desideri.

Personalmente, utilizzo spesso il linguaggio % ~ dp0% ~ 1 nel mio file batch, che interpreta il primo argomento relativo al percorso del batch in esecuzione. Tuttavia ha un difetto: fallisce miseramente se il primo argomento è pienamente qualificato.

Se è necessario supportare entrambi i percorsi assoluti relativi e , è possibile utilizzare La soluzione di Frédéric Ménez : cambia temporaneamente la directory di lavoro corrente.

Ecco un esempio che dimostrerà ciascuna di queste tecniche:

@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 lo salvi come c: \ temp \ example.bat e lo esegui da c: \ Users \ Public come

c: \ Users \ Public > \ temp \ example.bat .. \ windows

... osserverai il seguente output:

%~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"

la documentazione per l'insieme di modificatori consentiti su un argomento batch è disponibile qui: https://docs.microsoft.com/en- uS / windows-server / amministrazione / windows-comandi / chiamare

Altri suggerimenti

Stamattina ho riscontrato un'esigenza simile: come convertire un percorso relativo in un percorso assoluto all'interno di uno script di comandi di Windows.

Il trucco è stato il seguente:

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

La maggior parte di queste risposte sembrano pazze per complicati e super buggy, ecco la mia: funziona su qualsiasi variabile d'ambiente, senza % CD% o PUSHD / POPD o per / f senza senso - solo semplici funzioni batch precedenti. - La directory & amp; il file non deve nemmeno esistere.

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

ECHO "%BLAH%"

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

:NORMALIZEPATH
  SET RETVAL=%~dpfn1
  EXIT /B

Senza dover disporre di un altro file batch per passare argomenti (e utilizzare gli operatori argomento), è possibile utilizzare FOR / F :

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

dove i in %% ~ fi è la variabile definita in / F %% i . per esempio. se lo hai modificato in / F %% a , l'ultima parte sarebbe %% ~ fa .

Per fare la stessa cosa direttamente dal prompt dei comandi (e non in un file batch) sostituire %% con % ...

Questo serve a colmare le lacune nella risposta di Adrien Plisson (che dovrebbe essere votata non appena la modifica ;-):

  

puoi anche ottenere il percorso completo del tuo primo argomento usando% ~ f1, ma questo fornisce un percorso secondo il percorso corrente, che ovviamente non è quello che vuoi.

     

sfortunatamente, non so come mescolare i 2 insieme ...

Uno può gestire % 0 e % 1 allo stesso modo:

  • % ~ dpnx0 per unità completa + percorso + nome + estensione del file batch stesso,
    Anche % ~ f0 è sufficiente;
  • % ~ dpnx1 per unità completa + percorso + nome + estensione del suo primo argomento [se questo è un nome di file],
    Anche % ~ f1 è sufficiente;

% ~ f1 funzionerà indipendentemente da come hai specificato il tuo primo argomento: con percorsi relativi o con percorsi assoluti (se non specifichi l'estensione del file quando assegni un nome % 1 , non verrà aggiunto, anche se si utilizza % ~ dpnx1 - tuttavia.

Ma come faresti a nominare un file su un'unità diversa se non fornissi le informazioni sul percorso completo sulla riga di comando in primo luogo?

Tuttavia, % ~ p0 , % ~ n0 , % ~ nx0 e % ~ x0 potrebbero arrivare utile, se dovessi essere interessato a percorso (senza driveletter), nome file (senza estensione), nome file completo con estensione o solo estensione del nome file. Tuttavia, mentre % ~ p1 e % ~ n1 funzioneranno per scoprire il percorso o il nome del primo argomento, % ~ nx1 e % ~ x1 non aggiungerà + mostra l'estensione, a meno che non sia già stato utilizzato sulla riga di comando.

Puoi anche usare le funzioni batch per questo:

@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

Piccolo miglioramento alla l'eccellente soluzione di BrainSlugs83 . Generalizzato per consentire la denominazione della variabile di ambiente di output nella chiamata.

@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 eseguito da C: \ project l'output è:

C:\project\doc\build

Non ho visto molte soluzioni a questo problema. Alcune soluzioni utilizzano l'attraversamento di directory tramite CD e altre utilizzano funzioni batch. La mia preferenza personale è stata per le funzioni batch e, in particolare, la funzione MakeAbsolute come fornita di DosTips.

La funzione ha alcuni vantaggi reali, principalmente che non cambia la directory di lavoro corrente e in secondo luogo che i percorsi in fase di valutazione non devono nemmeno esistere. Puoi trovare alcuni suggerimenti utili su come utilizzare la funzione anche qui .

Ecco uno script di esempio e i suoi risultati:

@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 l'output:

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

Spero che questo aiuti ... Mi ha sicuramente aiutato :) Post scriptum Grazie ancora a DosTips! Fai rock!

Nel tuo esempio, da Bar \ test.bat, DIR / B / S .. \ somefile.txt restituisce il percorso completo.

Puoi semplicemente concatenarli.

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

sembra strano con \ .. \ nel mezzo del tuo percorso ma funziona. Non c'è bisogno di fare nulla di folle :)

PowerShell è piuttosto comune in questi giorni, quindi lo uso spesso come un modo rapido per invocare C # poiché ha funzioni per praticamente tutto:

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

È un po 'lento, ma la funzionalità acquisita è difficile da battere a meno che senza ricorrere a un vero linguaggio di scripting.

La soluzione di stijn funziona con le sottocartelle in C: \ Programmi (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%

File Visualizza tutte le altre risposte

Directory

Con .. come percorso relativo e supponendo che tu sia attualmente in D: \ Projects \ EditorProject :

cd .. & amp; cd & amp; cd EditorProject (il percorso relativo)

restituisce il percorso assoluto, ad esempio

D: \ Progetti

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top