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


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

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

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

или

dir *.txt /b /s >> C:temptest.txt

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

C:testDoc1.txt
C:testsubdirDoc2.txt
C:testsubdirDoc3.txt

Если Я делай

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

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

Doc1.txt
Doc2.txt
Doc3.txt

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

Doc1.txt
subdirDoc2.txt
subdirDoc3.txt

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

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

5 57

5 ответов:

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

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
)

самый простой (но не самый быстрый) способ итерации дерева каталогов и списка относительных путей к файлам-использовать 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

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


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

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

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

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

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

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

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

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

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

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