Я не чувствую себя виноватым, отвечая на этот домашний вопрос сейчас, когда семестр давно прошел. Рекурсивная печать папок и файлов с помощью Windows Batch - закрытый дубликат вопроса, в котором обсуждается назначение.
Мое первоначальное решение довольно простое. Есть несколько трюков, чтобы убедиться, что он правильно обрабатывает пути со специальными символами в них, но ничего особенного. Единственным другим приемом остается заполнение размера файла пробелами, чтобы SORT работал правильно.
Как и в первоначальном вопросе, 1-й параметр должен быть путем к папке (. \ Отлично работает), а последующие аргументы представляют имена файлов (подстановочные знаки в порядке).
@echo off
setlocal disableDelayedExpansion
set tempfile="%temp%\_mysort%random%.txt"
set "root="
for %%F in (%*) do (
if not defined root (
pushd %%F || exit /b
set root=1
) else (
echo(
echo %%~nxF
echo --------------------------------------------
(
@echo off
for /f "eol=: delims=" %%A in ('dir /s /b "%%~nxF"') do (
set "mypath=%%~dpA"
set "size= %%~zA"
setlocal enableDelayedExpansion
set "size=!size:~-12!"
echo !size! !mypath!
endlocal
)
) >%tempfile%
sort /r %tempfile%
)
)
if exist %tempfile% del %tempfile%
if defined root popd
Я надеялся избежать создания временного файла, заменив перенаправление и последующую сортировку на канал для прямой сортировки. Но это не работает. (см. мой связанный с этим вопрос: Почему отложенное расширение завершается неудачно, когда находится внутри переданного блока кода? )
Мое первое решение работает хорошо, за исключением того, что существует вероятность дублирования вывода в зависимости от того, какой ввод предоставляется. Я решил написать версию, отсеивающую дубликаты файловых отчетов.
Основная предпосылка была проста - сохранить все выходные данные в один временный файл с именем файла, добавленным в начало отсортированных строк. Затем мне нужно просмотреть результаты и выводить информацию только при изменении файла и / или пути.
Последний цикл - сложная часть, потому что имена файлов могут содержать специальные символы, такие как !
^
&
и %
, которые могут вызвать проблемы в зависимости от того, какой тип расширения используется. Мне нужно установить и сравнить переменные в цикле, который обычно требует отложенного расширения. Но задержанное расширение вызывает проблемы с расширением переменной FOR, когда найдено !
. Я могу избежать отложенного расширения, вызывая вне цикла, но тогда переменные FOR становятся недоступными. Я могу передать переменные в качестве аргументов подпрограмме CALLed без отложенного расширения, но затем у меня возникают проблемы с %
^
и &
. Я могу играть в игры с помощью SETLOCAL / ENDLOCAL, но тогда мне нужно беспокоиться о передаче значений через барьер ENDLOCAL, что требует довольно сложного процесса побега. Проблема становится большим порочным кругом.
Еще одно ограничение, которое я сам наложил, заключается в том, что я не хочу заключать вывод файла и пути в кавычки, так что это означает, что я должен использовать отложенное расширение, переменные FOR или экранированные значения.
Я нашел интересное решение, которое использует странную особенность переменных FOR.
Обычно область видимости переменных FOR находится внутри цикла. Если вы вызываете вне цикла, то значения переменной FOR больше не доступны. Но если вы затем выполните оператор FOR в вызываемой процедуре - переменные вызывающего оператора FOR снова станут видимыми! Проблема решена!
@echo off
setlocal disableDelayedExpansion
set tempfile="%temp%\_mysort%random%.txt"
if exist %tempfile% del %tempfile%
set "root="
(
for %%F in (%*) do (
if not defined root (
pushd %%F || exit /b
set root=1
) else (
set "file=%%~nxF"
for /f "eol=: delims=" %%A in ('dir /s /b "%%~nxF"') do (
set "mypath=%%~dpA"
set "size= %%~zA"
setlocal enableDelayedExpansion
set "size=!size:~-12!"
echo(!file!/!size!/!mypath!
endlocal
)
)
)
)>%tempfile%
set "file="
set "mypath="
for /f "tokens=1-3 eol=/ delims=/" %%A in ('sort /r %tempfile%') do call :proc
if exist %tempfile% del %tempfile%
if defined root popd
exit /b
:proc
for %%Z in (1) do (
if "%file%" neq "%%A" (
set "file=%%A"
set "mypath="
echo(
echo %%A
echo --------------------------------------------
)
)
for %%Z in (1) do (
if "%mypath%" neq "%%C" (
set "mypath=%%C"
echo %%B %%C
)
)
exit /b