windows - relativos - Resolver la ruta absoluta desde la ruta relativa y/o el nombre del archivo
ruta relativa java netbeans (14)
¿Hay alguna forma en una secuencia de comandos por lotes de Windows para devolver una ruta absoluta desde un valor que contiene un nombre de archivo y / o una ruta relativa?
Dado:
"../"
"../somefile.txt"
Necesito la ruta absoluta relativa al archivo por lotes.
Ejemplo:
- "somefile.txt" se encuentra en "C: / Foo /"
- "test.bat" se encuentra en "C: / Foo / Bar".
- El usuario abre una ventana de comando en "C: / Foo" y llama a
Bar/test.bat ../somefile.txt
- En el archivo por lotes, "C: / Foo / somefile.txt" se derivaría de
%1
En los archivos por lotes, como en los programas estándar C, el argumento 0 contiene la ruta al script en ejecución. Puede usar %~dp0
para obtener solo la parte de ruta del 0º argumento (que es el script actual); esta ruta es siempre una ruta totalmente calificada.
También puede obtener la ruta completa de su primer argumento utilizando %~f1
, pero esto le da una ruta de acuerdo con el directorio de trabajo actual, que obviamente no es lo que quiere.
Personalmente, a menudo uso la %~dp0%~1
en mi archivo por lotes, que interpreta el primer argumento relativo a la ruta del lote en ejecución. Sin embargo, tiene una deficiencia: fracasa rotundamente si el primer argumento está totalmente calificado.
Si necesita admitir rutas relativas y absolutas, puede utilizar la solución de Frédéric Ménez : cambiar temporalmente el directorio de trabajo actual.
Aquí hay un ejemplo que demostrará cada una de estas técnicas:
@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 guarda esto como c: / temp / example.bat y lo ejecuta desde c: / Users / Public como
c: / Users / Public> / temp / example.bat .. / windows
... observará la siguiente salida:
%~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"
En su ejemplo, desde Bar / test.bat, DIR / B / S .. / somefile.txt devolvería la ruta completa.
Encontré una necesidad similar esta mañana: cómo convertir una ruta relativa en una ruta absoluta dentro de un script de comando de Windows.
Lo siguiente hizo el truco:
@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%
Esto es para ayudar a llenar los vacíos en la respuesta de Adrien Plisson (que debe ser actualizada tan pronto como lo edite ;-):
también puede obtener la ruta completa de su primer argumento usando% ~ f1, pero esto le da una ruta de acuerdo con la ruta actual, que obviamente no es lo que quiere.
desafortunadamente, no sé cómo mezclar los 2 juntos ...
Uno puede manejar %0
y %1
mismo modo:
-
%~dpnx0
para drive + ruta + nombre + extensión totalmente calificada del archivo por lotes,
%~f0
también es suficiente; -
%~dpnx1
para unidad totalmente calificada + ruta + nombre + extensión de su primer argumento [si es un nombre de archivo],
%~f1
también es suficiente;
%~f1
funcionará independientemente de cómo hayas especificado tu primer argumento: con rutas relativas o con rutas absolutas (si no especificas la extensión del archivo al nombrar %1
, no se agregará, incluso si usas %~dpnx1
-- sin embargo.
Pero ¿cómo demonios nombrarías un archivo en una unidad diferente de todos modos si no le dieras esa información de ruta completa en la línea de comandos en primer lugar?
Sin embargo, %~p0
, %~n0
, %~nx0
y %~x0
pueden ser útiles, si está interesado en la ruta (sin letra de unidad), nombre de archivo (sin extensión), nombre de archivo completo con extensión o extensión de nombre de archivo solamente. Pero tenga en cuenta que mientras %~p1
y %~n1
trabajarán para descubrir la ruta o el nombre del primer argumento, %~nx1
y %~x1
no agregarán + mostrarán la extensión, a menos que ya la hayan utilizado en la línea de comandos.
La mayoría de estas respuestas parecen locas por complicadas y super buggy, aquí está la mía: funciona en cualquier variable de entorno, no %CD%
o PUSHD
/ POPD
, o for /f
absurdo, simplemente funciones antiguas de lotes. - El directorio y el archivo ni siquiera tienen que existir.
CALL :NORMALIZEPATH "../../../foo/bar.txt"
SET BLAH=%RETVAL%
ECHO "%BLAH%"
:: ========== FUNCTIONS ==========
EXIT /B
:NORMALIZEPATH
SET RETVAL=%~dpfn1
EXIT /B
La solución de stijn funciona con subcarpetas en 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%
No he visto muchas soluciones a este problema. Algunas soluciones hacen uso del recorrido de directorio usando CD y otras hacen uso de funciones de proceso por lotes. Mi preferencia personal ha sido para las funciones por lotes y, en particular, la función MakeAbsolute proporcionada por DosTips.
La función tiene algunos beneficios reales, principalmente que no cambia el directorio de trabajo actual y, en segundo lugar, que las rutas que se evalúan ni siquiera tienen que existir. Puede encontrar algunos consejos útiles sobre cómo usar la función here también.
Aquí hay un script de ejemplo y sus resultados:
@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
Y el resultado:
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
Espero que esto ayude ... Seguro que me ayudó :) PD ¡Gracias de nuevo a DosTips! ¡Rock!
Pequeña mejora a la excelente solución de BrainSlugs83 . Generalizado para permitir nombrar la variable de entorno de salida en la llamada.
@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 se ejecuta desde la salida C:/project
es:
C:/project/doc/build
PowerShell es bastante común en estos días, así que lo uso a menudo como una forma rápida de invocar C #, ya que tiene funciones para casi todo:
@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%
Es un poco lento, pero la funcionalidad obtenida es difícil de superar a menos que no se recurra a un lenguaje de scripting real.
Puedes concatenarlos.
SET ABS_PATH=%~dp0
SET REL_PATH=../SomeFile.txt
SET COMBINED_PATH=%ABS_PATH%%REL_PATH%
parece extraño con / .. / en el medio de tu camino, pero funciona. No hay necesidad de hacer nada loco :)
Sin tener que tener otro archivo por lotes para pasar argumentos a (y usar los operadores de argumento), puede usar FOR /F
:
FOR /F %%i IN ("../relativePath") DO echo absolute path: %%~fi
donde i
en %%~fi
es la variable definida en /F %%i
. p.ej. si cambió eso a /F %%a
entonces la última parte sería %%~fa
.
Para hacer lo mismo en el símbolo del sistema (y no en un archivo por lotes) reemplace %%
con %
...
También puede usar funciones de proceso por lotes para esto:
@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
Archivos Ver todas las demás respuestas
Directorios
Con ..
ser su ruta relativa, y suponiendo que se encuentre actualmente en D:/Projects/EditorProject
:
cd .. & cd & cd EditorProject
(la ruta relativa)
devuelve la ruta absoluta, por ejemplo
D:/Projects
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