Великолепные объяснения и решения от Mofi
Вот немного более короткий и более прямой способ достижения надежного решения, которое все еще опирается на фундаментальную технику Mofi использования FOR /F
tokens
и delims
, чтобы удалить путь root.
Мой код не позволяет указать указанный путь, в этом случае по умолчанию используется текущий каталог. Код для нормализации, проверки и извлечения необходимых значений из пути root значительно упрощен.
Я также использую совершенно другой метод подсчета количества токенов в пути root. Я заменяю символ новой строки \
, а затем подсчитываю количество строк с помощью FIND /C
, когда выводю значение. Это немного сложно, но очень эффективно и работает без обращения к GOTO
l oop.
. Я также сохраняю сообщение об ошибке, если файлы не найдены, и не беспокоюсь об удалении результирующий пустой файл.
@echo off
setlocal disableDelayedExpansion
::==== Get normalized values for supplied path in %1
::==== Default to current directory if not specified
for %%F in ("%~f1.") do ( %=== The trailing dot allows paths with/without trailing \ to work %
set "folder=%%~fF" ==== The normalized path for the root folder
set "archive=%%~nxF" ==== The base name of the output file
set "att=-%%~aF" ==== List of attributes for the root folder
)
::==== Validate path by checking for d in attributes
if %att:d=% == %att% (
>&2 echo Supplied path is invalid or not a folder
exit /b 1
)
::==== Special handling if drive root
if not defined archive (
set "archive=drive %folder:~0,1% root"
set cnt=1
goto start
)
::==== Normal processing for all other paths
setlocal enableDelayedExpansion
for %%L in (^"^
%==== Puts quoted newline in FOR variable L %
^") do set "folder2=!folder:\=%%~L!" ==== Substitutes newline for all \ in folder
::==== Count the number of tokens (lines) in folder2
setlocal disableDelayedExpansion
for /f %%N in ('"(cmd /v:on /c echo !folder2!)|find /c /v """') do set cnt=%%N
:start ==== Finally get the sorted list of files without root path
>"%archive%.$$$" (
for /f "delims=\ tokens=%cnt%*" %%A in ('dir "%folder%" /a:-d /b /o:n /s') do echo %%B
)
Код довольно лаконичен без комментариев и лишних пустых строк
@echo off
setlocal disableDelayedExpansion
for %%F in ("%~f1.") do (
set "folder=%%~fF"
set "archive=%%~nxF"
set "att=-%%~aF"
)
if %att:d=% == %att% (
>&2 echo Supplied path is invalid or not a folder
exit /b 1
)
if not defined archive (
set "archive=drive %folder:~0,1% root"
set cnt=1
goto start
)
setlocal enableDelayedExpansion
for %%L in (^"^
^") do set "folder2=!folder:\=%%~L!"
setlocal disableDelayedExpansion
for /f %%N in ('"(cmd /v:on /c echo !folder2!)|find /c /v """') do set cnt=%%N
:start
>"%archive%.$$$" (
for /f "delims=\ tokens=%cnt%*" %%A in ('dir "%folder%" /a:-d /b /o:n /s') do echo %%B
)
Мой оригинальный ответ не учитывал возможность подстановочных знаков при вводе. Подстановочные знаки можно исключить, добавив следующее после начальных SETLOCAL
for /f "delims=*?<> tokens=2" %%A in (".%~1.") do (
>&2 echo Wildcards * ? ^< and ^> not supported
exit /b 1
)
Обратите внимание, что "<"
и ">"
являются плохо документированными подстановочными знаками (только если они указаны в кавычках путь)!
Но Мофи описал интересное поведение, которого я никогда раньше не видел. Сначала я не мог понять, как C:\test\*
давал C:\
.
Это просто результат того, что %~f1
видит запись каталога .
в качестве первого указанного файла / папки в тестовой папке, и затем, когда мой код добавляет свою собственную точку, он становится C:\test\..
, что, конечно, нормализуется до C:\
.
Некоторое время я думал, что происходит специальная обработка, когда узел пути является ничем но подстановочные знаки, но я опубликовал поведение на DosTips , и респондент напомнил мне о записях каталога .
и ..
на всех дисках, кроме диска root.