Поиск файлов и сортировка по размеру в пакетном файле Windows - PullRequest
1 голос
/ 09 апреля 2011

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

Я уже сделал это, но это не работает:

::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 Ответ

6 голосов
/ 19 ноября 2011

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