ti-enxame.com

Arquivos em lote: lista todos os arquivos em um diretório com caminhos relativos

Referente aos arquivos em lote do Windows: Existe uma maneira de listar todos os arquivos (ou todos de um tipo específico) em um determinado diretório e seus subdiretórios, incluindo os caminhos relativos ao diretório atual (ou de pesquisa) na lista?

Por exemplo, se eu quiser todos os arquivos .txt no diretório atual e subdiretórios com seus caminhos completos, eu posso fazer

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

ou

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

e eu vou conseguir algo parecido

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

Se eu fizer

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

Eu vou conseguir algo como

Doc1.txt
Doc2.txt
Doc3.txt

Mas o que eu realmente quero é:

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

É possível?

Se o meu post é muito confuso: eu basicamente quero Lista de arquivos recursivamente no Linux CLI com o caminho em relação ao diretório atual, mas apenas para o Windows.

59
Tim Meyer

Você poderia simplesmente pegar o tamanho do caractere do diretório atual e removê-lo do seu 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
)
22
jeb

A maneira mais simples (mas não a mais rápida) de iterar uma árvore de diretórios e listar caminhos de arquivos relativos é usar FORFILES .

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

Os caminhos relativos serão citados com um .\ líder, como em

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


Para remover citações:

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


Para remover as citações e o .\ inicial:

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
)

ou sem usar a expansão atrasada

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

Essa resposta não funcionará corretamente com caminhos raiz contendo sinais de igual (=). (Obrigado @dbenham por apontar isso.)


EDITED: Corrigido o problema com caminhos contendo !, novamente manchado por @dbenham (obrigado!).

Como alternativa ao cálculo do comprimento e extração de substrings, você poderia usar uma abordagem diferente:

  • armazene o caminho da raiz;

  • limpe o caminho da raiz dos caminhos de arquivo.

Aqui está a minha tentativa (que funcionou para mim):

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

A variável r é atribuída com o diretório atual. A menos que o diretório atual seja o diretório raiz de uma unidade de disco, ele não terminará com \, que corrigimos adicionando o caractere.  (Não é mais o caso, pois o script agora lê a variável __CD__, cujo valor sempre termina com \ (obrigado @jeb!), Em vez de CD.)

No loop, armazenamos o caminho do arquivo atual em uma variável. Então nós produzimos a variável, removendo o caminho da raiz ao longo do caminho.

9
Andriy M

Claro, você pode escrever um algoritmo recursivo em Lote que lhe dá o controle exato do que você faz em cada subdiretório aninhado:

@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
5
Aacini
@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
)
3
Kedar