Подтвердить что ты не робот

Пакетные файлы: список всех файлов в каталоге с относительными путями

В отношении пакетных файлов Windows: есть ли способ перечислить все файлы (или все конкретного типа) в определенном каталоге и его подкаталогах, включая пути относительно текущей (или поисковой) директории в списке?

Например, если я хочу, чтобы все txt файлы в текущем каталоге и подкаталогах с их полными путями, я могу сделать

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

или

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

и я получу что-то вроде

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

Если я делаю

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

Я получу что-то вроде

Doc1.txt
Doc2.txt
Doc3.txt

Но я действительно хочу:

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

Возможно ли это?

Если мой пост слишком запутан: я в основном хочу "рекурсивно перечислить файлы в CLI Linux с контуром относительно текущего каталога", только для Windows.

4b9b3361

Ответ 1

Вы можете просто получить длину символа текущего каталога и удалить их из своего абсолютного списка

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
)

Ответ 2

Самый простой (но не самый быстрый) способ перебора дерева каталогов и списка относительных путей файла - использовать FORFILES.

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

Относительные пути будут указаны с ведущим .\, как в

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


Чтобы удалить кавычки:

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


Чтобы удалить кавычки и ведущие .\:

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
)

или без использования отложенного расширения

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

Ответ 3

Этот ответ не будет корректно работать с корневыми путями, содержащими равные знаки (=). (Спасибо @dbenham за указание на это.)


EDITED: Исправлена ​​проблема с путями, содержащими !, снова замеченными @dbenham (спасибо!).

Альтернативно для вычисления длины и извлечения подстрок вы можете использовать другой подход:

  • сохранить корневой путь;

  • очистить корневой путь от путей к файлу.

Здесь моя попытка (которая работала для меня):

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

Переменная r назначается текущим каталогом. Если текущий каталог не является корневым каталогом дискового накопителя, он не заканчивается на \, который мы исправляем добавлением символа. (больше не так, поскольку script теперь читает переменная __CD__, значение которой всегда заканчивается на \ (спасибо @jeb!) вместо CD.)

В цикле мы сохраняем текущий путь к переменной. Затем мы выводим переменную, удаляя корневой путь по пути.

Ответ 4

Конечно, вы можете написать рекурсивный алгоритм в Batch, который дает вам точный контроль над тем, что вы делаете в каждом вложенном подкаталоге:

@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

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