Batch Files: enumera todos los archivos en un directorio con rutas relativas

Acerca de los archivos Windows Batch: ¿hay alguna manera de enumerar todos los archivos (o todos los de un tipo específico) en un determinado directorio y sus subdirectorios, incluidas las rutas relativas al directorio actual (o de búsqueda) en la lista?

Por ejemplo, si quiero todos los archivos txt en el directorio actual y los subdirectorios con sus rutas completas, puedo hacer

for /r . %%g in (*.txt) do echo %%g >> C:\temp\test.txt 

o

 dir *.txt /b /s >> C:\temp\test.txt 

y obtendré algo así como

 C:\test\Doc1.txt C:\test\subdir\Doc2.txt C:\test\subdir\Doc3.txt 

Si lo hago

 for /r . %%g in (*.txt) do echo %%~nxg >> C:\temp\test.txt 

Voy a obtener algo como

 Doc1.txt Doc2.txt Doc3.txt 

Pero lo que realmente quiero es:

 Doc1.txt subdir\Doc2.txt subdir\Doc3.txt 

¿Es posible?

Si mi publicación es demasiado confusa: básicamente quiero ” Listar archivos recursivamente en la CLI de Linux con una ruta relativa al directorio actual “, solo para Windows.

Simplemente puede obtener la longitud de caracteres del directorio actual y eliminarlos de su lista absoluta

 setlocal EnableDelayedExpansion for /L %%n in (1 1 500) do if "!__cd__:~%%n,1!" neq "" set /a "len=%%n+1" setlocal DisableDelayedExpansion for /r . %%g in (*.log) do ( set "absPath=%%g" setlocal EnableDelayedExpansion set "relPath=!absPath:~%len%!" echo(!relPath! endlocal ) 

La manera más simple (pero no la más rápida) de iterar un árbol de directorios y enumerar rutas de archivos relativas es usar FORFILES .

 forfiles /s /m *.txt /c "cmd /c echo @relpath" 

Las rutas relativas se citarán con un encabezado .\ Como en

 ".\Doc1.txt" ".\subdir\Doc2.txt" ".\subdir\Doc3.txt" 

Para eliminar las cotizaciones:

 for /f %%A in ('forfiles /s /m *.txt /c "cmd /c echo @relpath"') do echo %%~A 

Para eliminar las comillas y el encabezado .\ :

 setlocal disableDelayedExpansion for /f "delims=" %%A in ('forfiles /s /m *.txt /c "cmd /c echo @relpath"') do ( set "file=%%~A" setlocal enableDelayedExpansion echo !file:~2! endlocal ) 

o sin usar expansión retardada

 for /f "tokens=1* delims=\" %%A in ( 'forfiles /s /m *.txt /c "cmd /c echo @relpath"' ) do for %%F in (^"%%B) do echo %%~F 

Esta respuesta no funcionará correctamente con rutas raíz que contengan signos iguales ( = ). (Gracias @dbenham por señalar eso).


EDITADO: se corrigió el problema con las rutas que contenían ! , nuevamente visto por @dbenham (¡gracias!).

Alternativamente al cálculo de la longitud y la extracción de subcadenas, podría utilizar un enfoque diferente:

  • almacenar la ruta raíz;

  • borre la ruta raíz de las rutas de archivos.

Aquí está mi bash (que funcionó para mí):

 @ECHO OFF SETLOCAL DisableDelayedExpansion SET "r=%__CD__%" FOR /R . %%F IN (*) DO ( SET "p=%%F" SETLOCAL EnableDelayedExpansion ECHO(!p:%r%=! ENDLOCAL ) 

La variable r se asigna con el directorio actual. A menos que el directorio actual sea el directorio raíz de una unidad de disco, no terminará con \ , que modificaremos al agregar el carácter. (Ya no es el caso, ya que el script ahora lee la variable __CD__ , cuyo valor siempre termina con \ (gracias @jeb!), En lugar de CD .)

En el ciclo, almacenamos la ruta del archivo actual en una variable. Luego damos salida a la variable, eliminando el camino raíz a lo largo del camino.

Por supuesto, puede escribir un algoritmo recursivo en Batch que le dé un control exacto de lo que hace en cada subdirectorio nested:

 @echo off set mypath= call :treeProcess goto :eof :treeProcess setlocal for %%f in (*.txt) do echo %mypath%%%f for /D %%d in (*) do ( set mypath=%mypath%%%d\ cd %%d call :treeProcess cd .. ) endlocal exit /b 
 @echo on>out.txt @echo off setlocal enabledelayedexpansion set "parentfolder=%CD%" for /r . %%g in (*.*) do ( set "var=%%g" set var=!var:%parentfolder%=! echo !var! >> out.txt )