Если вы можете справиться с этим, избегайте этой путаницы, взяв утилиту Sysinternals du и запустив du -v <directoryname>
. Вывод будет килобайт. Опция -v
означает вывод размера всех подкаталогов.
В вашем текущем сценарии проблема заключается в добавлении текста в цикле. Простой обходной путь - вывести в окно командной строки, вот так:
echo %%q
echo !xsize!
и когда вы запускаете пакетный файл, отправляете его вывод в текстовый файл: test.bat > size.txt
Быстрый совет: первый бит можно упростить с помощью:
for /f "tokens=*" %%q in ('dir /a:d /s /b') do (
cd "%%q"
...
echo !xsize!
)
По сути, он заменяет использование find
параметром /a:d
(только для списков каталогов) и /b
(использовать пустой формат, без заголовка или сводки). Это также избавляет от временного файла.
Модифицированная версия для работы с папками с восклицательными знаками в названии. Используя ответ Скотта. Смотрите комментарии ниже.
Обратите внимание, что REM
означает, что это комментарий.
@echo off
REM clear the file
type NUL > size.txt
for /f "tokens=*" %%q IN ('dir /a:d /s /b') do (
echo %%q >> size.txt
REM Run :getsize, passing "%%q" including quotes as the first parameter
call :getsize "%%q" >> size.txt
)
REM go to the end of the file, i.e. exit
goto :eof
:getsize
REM %1 is the first parameter. It should already be quoted.
for /f "tokens=*" %%h IN ('"dir /s /-c /a %1 | find "bytes" | find /v "free""') do set xsummary=%%h
for /f "tokens=1,2 delims=)" %%a in ("%xsummary%") do set xsize=%%b
set xsize=%xsize:bytes=%
set xsize=%xsize: =%
echo %xsize%
goto :eof
Альтернативой является использование PowerShell:
Get-ChildItem -Recurse | ?{ $_.PSIsContainer } | %{$_ | Add-Member -MemberType NoteProperty -Name DirSize -Value 0; $_.DirSize = $(Get-ChildItem -Recurse $_.Fullname | ?{ -not $_.PSIsContainer } | Measure-Object -Sum -Property Length).Sum; $_} | Sort-Object DirSize -Descending | Select-Object -First 10 FullName,DirSize | Format-Table -AutoSize | Out-String -Width 4096 | Out-File 'sizes.txt';
Это слишком сложно для того, чтобы быть как можно более полным - также большинство этих команд имеют более короткие псевдонимы; это просто более читабельно. И если вы разделите определенные разделы на функции / их собственную строку, это станет намного более читабельным и, возможно, короче.
Расширяя это:
Get-ChildItem -Recurse
Рекурсивный список всех подкаталогов и файлов
?{ $_.PSIsContainer }
Фильтр, поэтому сохраняются только каталоги (?
является псевдонимом для Where-Object
). $_
ссылается на объект (ы), переданный по этому каналу - поскольку Get-ChildItem
передает список / массив объектов, он обрабатывает их по одному за раз.
%{$_ | Add-Member -MemberType NoteProperty -Name DirSize -Value 0; $_.DirSize = $(Get-ChildItem -Recurse $_.Fullname | ?{ -not $_.PSIsContainer } | Measure-Object -Sum -Property Length).Sum; $_}
Рассчитать размер каждого каталога (%
является псевдонимом для Foreach-Object
, поэтому запустите то, что находится между { }
для каждого отдельного объекта. Каждый объект является каталогом, как в предыдущих частях.)
Расширяя это:
$_ | Add-Member -MemberType NoteProperty -Name DirSize -Value 0;
Точка с запятой (;
) обозначает конец строки / оператора и не передает выходные данные, в отличие от канала (|
). Этот конкретный бит не имеет вывода, и он просто добавляет свойство DirSize
к объекту каталога и инициализирует его в 0. Это сделано для более легкой фильтрации и более аккуратного вывода позже.
$_.DirSize = $(Get-ChildItem -Recurse $_.Fullname | ?{ -not $_.PSIsContainer } | Measure-Object -Sum -Property Length).Sum;
Установите DirSize
в свойство Sum
выходных данных этой команды. $()
означает выполнить то, что находится внутри скобок, и заменить это на.
Расширяя это:
Get-ChildItem -Recurse $_.Fullname
Получить все содержимое текущего объекта каталога ($_
, Fullname
просто означает полный путь). -Recurse
означает также подсчитывать содержимое подкаталогов.
?{ -not $_.PSIsContainer }
Фильтруйте так, чтобы сохранялись только файлы. Каталоги имеют свойство Length
равное 0, поэтому нам нужно использовать sum для файлов внутри - по сути, то, что делает ваш пакетный скрипт, за исключением того, что мы имеем дело с реальными числами, объектами и свойствами, вместо того, чтобы захватывать «число» как текст с помощью find
.
Measure-Object -Sum -Property Length
Вычислить сумму всех переданных ему свойств Length
. Это возвращает объект, содержащий свойство Sum
, которое использовалось выше (.Sum
)
$_
По сути, echo
объект, чтобы передать его следующему разделу. Теперь у него есть свойство DirSize
.
Sort-Object DirSize -Descending
Сортировать по убыванию по DirSize
Select-Object -First 10 FullName,DirSize
Выведите только первые 10, и только имя и размер
Format-Table -AutoSize | Out-String -Width 4096 | Out-File 'sizes.txt';
Вывод в sizes.txt
. Биты Format-Table
и Out-String
предназначены для предотвращения усечения до ширины окна консоли (обычно 80 символов). 4096 должно быть более чем достаточно символов для любого пути Windows и размера каталога, учитывая, что путь Windows обычно ограничен 255 символами (IIRC). AutoSize
означает просто сделать его как можно более коротким, без усечения, вместо заполнения большим количеством пробелов для размещения 4096 символов.
И команда в виде однострочного запуска в cmd.exe
(вы можете запустить вышеуказанную версию в PowerShell):
powershell -c "Get-ChildItem -Recurse | ?{ $_.PSIsContainer } | %{$_ | Add-Member -MemberType NoteProperty -Name DirSize -Value 0; $_.DirSize = $(Get-ChildItem -Recurse $_.Fullname | ?{ -not $_.PSIsContainer } | Measure-Object -Sum -Property Length).Sum; $_} | Sort-Object DirSize -Descending | Select-Object -First 10 FullName,DirSize | Format-Table -AutoSize | Out-String -Width 4096 | Out-File 'sizes.txt';"