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';"