2011-12-05 14 views
55

Acerca de los archivos por lotes de Windows: ¿Hay alguna manera de enumerar todos los archivos (o todos los tipos específicos) en un directorio determinado y sus subdirectorios, incluidas las rutas relativas a el directorio actual (o el de búsqueda) en la lista?Archivos por lotes: enumere todos los archivos en un directorio con rutas relativas

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

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

o

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

y voy a conseguir algo como

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

Si hago

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

voy a conseguir 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 "List files recursively in Linux CLI with path relative to the current directory", solo para Windows.

Respuesta

22

Se puede conseguir simplemente 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 
) 
+0

'set "absPath = %% g"' falla si la ruta contiene '!'. Se puede arreglar con alternar la expansión retardada. – dbenham

+3

Se arregló el problema '!', Era perezoso, pensando que no se le ocurriría a nadie – jeb

9

Esta respuesta no funcionará correctamente con las rutas de raíz que contiene el signo igual (=). (Gracias @dbenham por señalarlo.)


EDITADO: ha solucionado el problema con rutas que contienen !, nuevamente descubierto por @dbenham (gracias!).

Como alternativa al cálculo de la longitud y extraer subcadenas se puede utilizar un enfoque diferente:

  • tienda de la ruta raíz;

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

Aquí está mi intento (que trabajó 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 le asigna 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 en \ (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.

+0

Esto no funcionará si la ruta de la raíz contiene '=', pero de lo contrario debería ser buena. – dbenham

+0

Supuse que '' 's' '' 's' '' '' '' s '' '' '' '' '' '' '' '' '' ' Gracias por su nota, lo estoy agregando a mi respuesta. –

+0

La línea 4 debe ser 'IF NOT"% r: ~ -1% "==" \ "SET" r =% r% \ "' – dbenham

4

Por supuesto, es posible escribir un algoritmo recursivo en el lote que le da un control exacto de lo que haces en cada subdirectorio anidado:

@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 
+0

Obras como el encanto! Me gusta este enfoque :-) –

+0

así como a primera vista parece menos peligroso que los trucos de expansión demorados – grenix

30

El (pero no la más rápida) forma más sencilla de recorrer 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 cotizará con un líder .\ como en

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


cotizaciones para quitar:

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


Para eliminar las citas y el principal .\:

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 el uso de 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 
+0

tu solución funciona cuando envío los valores a cmd pero si echo '@ relpath >> cache.appcache' , solo se muestran los archivos en el directorio principal. ¿Sabes lo que podría estar causando eso? – rory

+0

@rory - No es una pista.Si está seguro de no haber olvidado usar la opción/S, entonces eso suena digno de una nueva pregunta. – dbenham

+0

definitivamente no, emite los subdirectores a la ventana de cmd pero no al archivo txt. Voy a publicar una nueva pregunta, así que, gracias por su ayuda – rory

2
@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 
) 
Cuestiones relacionadas