Question

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?

Donné:

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

J'ai besoin du chemin absolu relatif au fichier de commandes.

Exemple:

  • " somefile.txt " se trouve dans "C: \ Foo \"
  • " test.bat " se trouve dans "C: \ Foo \ Bar".
  • L'utilisateur ouvre une fenêtre de commande dans " C: \ Foo " et appelle Bar \ test.bat .. \ somefile.txt
  • Dans le fichier de commandes " C: \ Foo \ somefile.txt " serait dérivé de % 1
Était-ce utile?

La solution

Dans les fichiers batch, 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 complet.

Vous pouvez également obtenir le chemin qualifié complet de votre premier argument en utilisant % ~ f1 , mais cela donne un chemin en fonction du répertoire de travail actuel, 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 N ° 233; d & # 233; ric M & # 233; solution de nez : modifie temporairement le répertoire de travail en cours.

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 en tant que 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 des modificateurs autorisés sur un argument de lot peut être trouvée ici: https://docs.microsoft.com/en- nous / windows-server / administration / windows-orders / call

Autres conseils

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 l'affaire:

@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 la super complication et du super buggy, voici la mienne - cela fonctionne sur toutes les variables d'environnement, pas de % CD% ni PUSHD / POPD ou pour / f absurdité - tout simplement de vieilles fonctions de traitement par lots. - Le répertoire & amp; fichier ne doit 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

i dans %% ~ fi est la variable définie dans / F %% i . par exemple. Si vous avez changé cela en / F %% a , la dernière partie serait %% ~ fa .

Pour faire la même chose directement à l'invite de commande (et non dans un fichier de commandes), remplacez %% par % ...

C'est pour aider à combler les lacunes de 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 gérer % 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 [s'il s'agit d'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 lors de l'attribution du nom à % 1 , il ne sera pas ajouté, même si vous utilisez % ~ dpnx1 - cependant.

Mais comment pourriez-vous nommer un fichier sur un lecteur différent si vous ne donniez pas les informations de chemin complet sur la ligne de commande en premier lieu?

Cependant, % ~ p0 , % ~ n0 , % ~ nx0 et % ~ x0 peuvent arriver pratique, si vous êtes intéressé par chemin (sans driveletter), 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 permettent de connaître le chemin ou le nom du premier argument, % ~ nx1 et % ~ x1 n'ajoutera pas + affichera l'extension, sauf si vous l'avez 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

Légère amélioration par rapport à l'excellente solution de BrainSlugs83 . 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é depuis C: \ projet , 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 telle qu'elle est 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 que les chemins évalués ne doivent même pas exister. Vous pouvez trouver des conseils utiles sur l’utilisation de la fonction ici aussi.

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 ça aide ... Ça m'a bien aidé :) P.S. Merci encore à DosTips! Vous basculez!

Dans votre exemple, dans Bar \ test.bat, DIR / B / S .. \ somefile.txt renverrait le chemin complet.

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:)

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 la fonctionnalité acquise est difficile à battre si vous n’utilisez pas un langage de script réel.

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%

Fichiers Voir toutes les autres réponses

Répertoires

Avec .. comme chemin relatif et si vous vous trouvez actuellement dans D: \ Projects \ EditorProject :

cd .. & amp; cd & amp; cd EditorProject (le chemin relatif)

renvoie le chemin absolu, par exemple.

D: \ Projets

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top