Поиск файлов и сортировка по размеру в пакетном файле Windows

В качестве параметров командной строки для моего пакетного скрипта у меня есть список имен файлов и папок. Для каждого имени файла мне нужно распечатать все подпапки папки, в которой находится файл (путь к этому файлу). Имена подпапок должны быть отсортированы в порядке убывания размеров файлов (файл может иметь разные размеры в разных подпапках).

Я сделал это до сих пор, но это не работает:

::verify if the first parameter is the directory

@echo off
REM check the numbers of parameters
if "%2"=="" goto err1
REM check: is first parameter a directory?
if NOT EXIST %1\NUL goto err2
set d=%1
shift
REM iterate the rest of the parameters


for %%i in %dir  do (
find %dir /name %i > temp

if EXIST du /b temp | cut /f 1 goto err3 
 myvar=TYPE temp
echo "file " %i "is in: "

for %%j in %myvar do
 echo %j

 echo after sort
du /b %myvar | sort /nr       
)

:err1
echo Two parameters are necessary 
goto end

:err2
echo First parameter must be a directory.
goto end

:err3 
echo file does not exist.
goto end

:end

1 ответ

Решение

Я не чувствую себя виноватым, отвечая на этот домашний вопрос теперь, когда семестр давно прошел. Рекурсивная печать папок и файлов с использованием 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
Другие вопросы по тегам