Se conseguir gerenciá-lo, evite essa bagunça pegando o utilitário Sysinternals du e executando du -v <directoryname>
. A saída será de kilobytes. A opção -v
significa a saída do tamanho de todos os subdiretórios.
Com o seu script atual, o problema parece estar anexando texto em um loop. Uma solução fácil é a saída para a janela do prompt de comando, da seguinte forma:
echo %%q
echo !xsize!
e quando você executa o arquivo em lote, envia sua saída para um arquivo de texto: test.bat > size.txt
Uma dica rápida: o primeiro bit pode ser simplificado com:
for /f "tokens=*" %%q in ('dir /a:d /s /b') do (
cd "%%q"
...
echo !xsize!
)
Basicamente, ele está substituindo o uso de find
pela opção /a:d
(somente diretórios de lista) e /b
(use formato simples, sem título ou resumo). Isso também elimina o arquivo temporário.
Versão modificada para trabalhar em pastas com pontos de exclamação no nome. Usando a resposta de Scott. Veja os comentários abaixo.
Note que REM
significa que é um comentário.
@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
Uma alternativa é usar o 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';
Isso é excessivamente complexo com o propósito de ser o mais completo possível - também, a maioria desses comandos tem aliases mais curtos; isso é apenas mais legível. E se você separar determinadas seções em funções / sua própria linha, ela se tornará muito mais legível e possivelmente mais curta.
Expandindo:
-
Get-ChildItem -Recurse
Listar recursivamente todos os subdiretórios e arquivos
-
?{ $_.PSIsContainer }
Filtre apenas os diretórios mantidos ( ?
é um alias para Where-Object
). $_
refere-se ao (s) objeto (s) canalizado (s) para isso - como Get-ChildItem
passa uma lista / array de objetos, isso os processa um de cada vez.
-
%{$_ | Add-Member -MemberType NoteProperty -Name DirSize -Value 0; $_.DirSize = $(Get-ChildItem -Recurse $_.Fullname | ?{ -not $_.PSIsContainer } | Measure-Object -Sum -Property Length).Sum; $_}
Calcule o tamanho de cada diretório ( %
é um alias para Foreach-Object
, portanto, execute o que está entre { }
em cada objeto individual. Cada objeto é um diretório, conforme as partes anteriores).
Expandindo:
-
$_ | Add-Member -MemberType NoteProperty -Name DirSize -Value 0;
Um ponto-e-vírgula ( ;
) indica o fim de uma linha / instrução e não passa a saída, em oposição a um canal ( |
). Esse bit em particular não tem saída, e é apenas adicionar a propriedade DirSize
ao objeto de diretório e inicializá-lo para 0. Isso é feito para facilitar a filtragem e a saída mais pura posteriormente.
-
$_.DirSize = $(Get-ChildItem -Recurse $_.Fullname | ?{ -not $_.PSIsContainer } | Measure-Object -Sum -Property Length).Sum;
Defina DirSize
como a propriedade Sum
da saída desse comando. $()
significa executar o que está dentro dos parênteses e substituí-lo por.
Expandindo:
-
Get-ChildItem -Recurse $_.Fullname
Obtenha todo o conteúdo do objeto de diretório atual ( $_
, Fullname
significa apenas o caminho completo). -Recurse
significa também contar o conteúdo dos subdiretórios.
-
?{ -not $_.PSIsContainer }
Filtre para que apenas os arquivos sejam mantidos. Diretórios têm uma propriedade Length
de 0, então precisamos usar soma dos arquivos dentro - essencialmente o que seu script em lote faz, exceto que estamos lidando com números reais, objetos e propriedades em vez de pegar um 'número' como texto usando find
.
-
Measure-Object -Sum -Property Length
Calcule a soma de todas as propriedades Length
passadas para ele. Isso retorna um objeto contendo a propriedade Sum
, que é usada acima ( .Sum
)
-
$_
Essencialmente echo
ing o objeto para passá-lo para a próxima seção. Agora ele tem uma propriedade DirSize
.
-
Sort-Object DirSize -Descending
Classificar descendente por DirSize
-
Select-Object -First 10 FullName,DirSize
Somente imprima os 10 primeiros e somente o nome e o tamanho
-
Format-Table -AutoSize | Out-String -Width 4096 | Out-File 'sizes.txt';
Saída para sizes.txt
. Os bits Format-Table
e Out-String
são para impedir o truncamento na largura da janela do console (normalmente 80 caracteres). 4096 deve ser mais do que caracteres suficientes para qualquer caminho do Windows e tamanho de diretório, considerando que um caminho do Windows é normalmente limitado a 255 caracteres (IIRC). O AutoSize
significa apenas torná-lo o mais curto possível sem truncar, em vez de preenchimento com um monte de espaços em branco para caber 4096 caracteres.
E o comando como um liner para executar em cmd.exe
(você pode executar a versão acima no 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';"