Risolvi il percorso assoluto dal percorso relativo e / o dal nome del file
-
22-07-2019 - |
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
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