web-dev-qa-db-fra.com

Résoudre le chemin absolu du chemin relatif et / ou du nom de fichier

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:

  • "somefile.txt" est situé 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
146
Nathan Taylor

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

152
Adrien Plisson

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%
139
Frédéric Ménez

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
80
BrainSlugs83

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, 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 %...

35
Peter Ritchie

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.

15
Kurt Pfeifle

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
9
Axel Heider

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
8
Lycan

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!

4
dayneo

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

1
Kristen

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

1
George Sisco

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%
0
Irq Mishell
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
0
Sergei Sachkov

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

0
Engineer

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.

0
stijn