Existe-t-il un moyen dans un script batch Windows de renvoyer un chemin absolu à partir d'une valeur contenant un nom de fichier et/ou un chemin relatif?
Étant donné:
"..\"
"..\somefile.txt"
J'ai besoin du chemin absolu par rapport au fichier de commandes.
Exemple:
Bar\test.bat ..\somefile.txt
%1
Dans les fichiers de commandes, comme dans les programmes C standard, l'argument 0 contient le chemin d'accès au script en cours d'exécution. Vous pouvez utiliser %~dp0
pour obtenir uniquement la partie chemin de l'argument 0 (qui est le script actuel). Ce chemin est toujours un chemin qualifié complet.
Vous pouvez également obtenir le chemin qualifié complet de votre premier argument en utilisant %~f1
, mais vous obtiendrez un chemin en fonction du répertoire de travail en cours, ce qui n'est évidemment pas ce que vous voulez.
Personnellement, j'utilise souvent l'idiome %~dp0%~1
dans mon fichier batch, qui interprète le premier argument relatif au chemin du lot en cours d'exécution. Il a cependant un inconvénient: il échoue lamentablement si le premier argument est pleinement qualifié.
Si vous devez prendre en charge les chemins absolus relatifs et , vous pouvez utiliser solution de Frédéric Ménez : modifier temporairement le travail en cours. annuaire.
Voici un exemple illustrant chacune de ces techniques:
@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
Si vous enregistrez ceci sous le nom c:\temp\example.bat et l’exécutez à partir de c:\Utilisateurs\Public en tant que
c:\Utilisateurs\Public>\temp\example.bat ..\windows
... vous observerez la sortie suivante:
%~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 documentation pour l'ensemble de modificateurs autorisés sur un argument batch peut être trouvée ici: https://docs.Microsoft.com/en-us/windows-server/administration/windows-commands/call
Je suis tombé sur un besoin similaire ce matin: comment convertir un chemin relatif en un chemin absolu dans un script de commande Windows.
Ce qui suit a fait le tour:
@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 plupart de ces réponses semblent loufoques à propos de super compliqué et de super buggy, voici la mienne - cela fonctionne sur n’importe quelle variable d’environnement, pas de %CD%
ou PUSHD
/POPD
, ni de for /f
un non-sens - - Juste les vieilles fonctions de traitement par lots. - Le répertoire et le fichier ne doivent même pas exister.
CALL :NORMALIZEPATH "..\..\..\foo\bar.txt"
SET BLAH=%RETVAL%
ECHO "%BLAH%"
:: ========== FUNCTIONS ==========
EXIT /B
:NORMALIZEPATH
SET RETVAL=%~dpfn1
EXIT /B
Sans avoir à utiliser un autre fichier de commandes où transmettre des arguments (et utiliser les opérateurs d'argument), vous pouvez utiliser FOR /F
:
FOR /F %%i IN ("..\relativePath") DO echo absolute path: %%~fi
où i
dans %%~fi
est la variable définie dans /F %%i
. par exemple. Si vous avez changé cela en /F %%a
, alors la dernière partie serait %%~fa
.
Pour faire la même chose à la commande Invite (et non dans un fichier de commandes), remplacez %%
par %
...
C'est pour aider à combler les lacunes dans la réponse d'Adrien Plisson (qui devrait être voté dès qu'il l'éditera ;-):
vous pouvez également obtenir le chemin qualifié complet de votre premier argument en utilisant% ~ f1, mais cela donne un chemin correspondant au chemin actuel, ce qui n'est évidemment pas ce que vous voulez.
malheureusement, je ne sais pas comment mélanger les 2 ensemble ...
On peut manipuler %0
et %1
de la même manière:
%~dpnx0
pour le lecteur qualifié complet + chemin + nom + extension du fichier batch lui-même,%~f0
suffit également;%~dpnx1
pour le lecteur qualifié complet + chemin + nom + extension de son premier argument [si c'est un nom de fichier],%~f1
suffit également;%~f1
fonctionnera indépendamment de la manière dont vous avez spécifié votre premier argument: avec des chemins relatifs ou absolus (si vous ne spécifiez pas l'extension du fichier lorsque vous nommez %1
, il ne sera pas ajouté, même si vous utilisez %~dpnx1
- cependant.
Mais comment diable nommeriez-vous un fichier sur un autre lecteur de toute façon si vous ne donniez pas ce chemin complet sur la ligne de commande en premier lieu?
Cependant, %~p0
, %~n0
, %~nx0
et %~x0
peuvent être utiles, si vous êtes intéressé par chemin (sans lecteur de code), nom de fichier (sans extension), nom de fichier complet avec extension ou extension du nom de fichier uniquement. Mais notez bien que %~p1
et %~n1
trouveront le chemin ou le nom du premier argument, %~nx1
et %~x1
n’ajouteront pas + afficheront l’extension, sauf si déjà utilisé sur la ligne de commande.
Vous pouvez également utiliser des fonctions de traitement par lots pour cela:
@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
Petite amélioration à excellente solution de BrainSlugs8 . Généralisé pour permettre de nommer la variable d'environnement de sortie dans l'appel.
@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
Si exécuté à partir de C:\project
, la sortie est:
C:\project\doc\build
Je n'ai pas vu beaucoup de solutions à ce problème. Certaines solutions utilisent la traversée de répertoires à l'aide de CD et d'autres utilisent des fonctions de traitement par lots. Ma préférence personnelle a été pour les fonctions de traitement par lots et en particulier, la fonction MakeAbsolute fournie par DosTips.
La fonction présente de réels avantages, notamment le fait qu'elle ne modifie pas votre répertoire de travail actuel et, deuxièmement, que les chemins évalués ne doivent même pas exister. Vous pouvez trouver des conseils utiles sur l’utilisation de la fonction ici .
Voici un exemple de script et ses sorties:
@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
Et la sortie:
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
J'espère que cela aide ... Cela m'a certainement aidé :) P.S. Merci encore à DosTips! Tu gères!
Vous pouvez simplement les concaténer.
SET ABS_PATH=%~dp0
SET REL_PATH=..\SomeFile.txt
SET COMBINED_PATH=%ABS_PATH%%REL_PATH%
ça a l'air bizarre avec\..\au milieu de votre chemin mais ça marche. Pas besoin de faire quelque chose de fou :)
Dans votre exemple, dans Bar\test.bat, DIR/B/S ..\somefile.txt renverrait le chemin complet.
la solution de stijn fonctionne avec des sous-dossiers sous 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%
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
Fichiers Voir toutes les autres réponses
Répertoires
Avec ..
comme chemin relatif et en supposant que vous êtes actuellement dans D:\Projects\EditorProject
:
cd .. & cd & cd EditorProject
(le chemin relatif)
renvoie le chemin absolu, par exemple.
D:\Projects
PowerShell est assez courant de nos jours, je l'utilise donc souvent comme un moyen rapide d'invoquer C #, car il a des fonctions pour à peu près tout:
@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%
C'est un peu lent, mais les fonctionnalités acquises sont difficiles à battre si vous n'utilisez pas un langage de script réel.