Ответ 1
Я не чувствую себя виноватым, отвечая на этот вопрос о домашнем задании сейчас, когда семестр давно прошло. Печатать папки и файлы, рекурсивно используя пакет Windows, является закрытым дублирующимся вопросом, который обсуждает назначение.
Мое первоначальное решение довольно прямолинейно. Есть несколько трюков, чтобы убедиться, что он правильно обрабатывает пути со специальными символами в них, но ничего необычного. Единственный трюк - это оставить размер файла пробелами, чтобы СОРТ работал правильно.
Как и в исходном вопросе, первым параметром должен быть путь к папке (.\works just fine), а последующие аргументы представляют имена файлов (подстановочные знаки в порядке).
@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 в вызываемой процедуре - переменные вызывающего оператора 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