Não é possível exportar para o arquivo na linha de comando do Windows

1

No código a seguir, preciso levar o caminho e o tamanho da pasta e das subpastas para um arquivo. Mas quando o loop é executado pela segunda vez, o caminho e o tamanho não são impressos no arquivo. size.txt contém apenas o caminho e o tamanho da primeira pasta. Por favor, alguém me ajude.

@echo off

SETLOCAL EnableDelayedExpansion
SET xsummary=
SET xsize=

for /f "tokens=1,2 delims=C" %%i IN ('"dir /s /-c /a | find "Directory""') do (echo    C%%j >> abcd.txt)
for /f "tokens=*" %%q IN (abcd.txt) do (
cd "%%q"
For /F "tokens=*" %%h IN ('"dir /s /-c /a | 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.%%q >> size.txt
echo.!xsize! >> size.txt

    
por Sachin 10.10.2012 / 17:09

2 respostas

1

O problema é o cd - você está criando um arquivo size.txt de duas linhas em cada diretório. Experimente

for ... %%h in ('"dir /s /-c /a  %%q  | find "bytes" | find /v "free""') ...

e remova o cd .

A propósito, você percebe que está obtendo totais cumulativos? Por exemplo, se sua estrutura de diretório se parece com

a   100K
a\b 200K
a\c 400K

então o seu resultado vai dizer

a
700000
a\b
200000
a\c
400000

Isso porque o segundo dir tem a opção /s . Tudo bem, se é isso que você quer; Eu apenas pensei que poderia ter sido um descuido.

    
por 10.10.2012 / 18:55
1

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';"
    
por 10.10.2012 / 18:17