Nie można wyprowadzić pliku do pliku w wierszu polecenia systemu Windows

1

W poniższym kodzie muszę wziąć ścieżkę i rozmiar folderu i podfolderów do pliku. Ale gdy pętla działa po raz drugi, ścieżka i rozmiar nie są drukowane do pliku. size.txt zawiera tylko ścieżkę i rozmiar pierwszego folderu. Proszę, niech ktoś mi pomoże.

@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

)

Sachin
źródło

Odpowiedzi:

1

Problem w tym, cdże - tworzysz plik dwuwierszowy size.txtw każdym katalogu. Próbować

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

i usuń cd.

Nawiasem mówiąc, czy zdajesz sobie sprawę, że otrzymujesz skumulowane sumy? Na przykład, jeśli wygląda struktura katalogów

100 tys
a \ b 200 tys
a \ c 400 tys

wtedy twój wynik powie

za
700000
a \ b
200000
a \ c
400000

To dlatego, że drugi dirma /sopcję. W porządku, jeśli tego właśnie chcesz; Pomyślałem, że to może być przeoczenie.

Scott
źródło
Dzięki Scott. Zapomniałem o tej nazwie „cd”. Twoja metoda zadziałała z niewielką zmianą. Podałem jako „%% q”, aby uwzględnić foldery, których nazwy zawierają spacje. I tak, potrzebuję tylko wyniku skumulowanego. Dzięki za troskę.
Sachin,
@Sachin: I dzięki za przypomnienie mi o cytatach. Najpierw jestem osobą uniksową i odruchowo cytuję zmienne w skryptach powłoki, ale ciągle zapominam o tym w DOS-ie. Mam na myśli wiersz poleceń systemu Windows.
Scott,
1

Jeśli dasz radę, uniknij tego bałaganu, chwytając narzędzie Sysinternals du i uruchamiając du -v <directoryname>. Dane wyjściowe będą kilobajtami. -vOpcja środków wyjściowych rozmiar wszystkich podkatalogów.


W obecnym skrypcie problemem wydaje się dodawanie tekstu w pętli. Łatwym obejściem jest wyjście do okna wiersza poleceń, na przykład:

echo %%q
echo !xsize!

a po uruchomieniu pliku wsadowego wysłano jego wynik do pliku tekstowego: test.bat > size.txt


Szybka wskazówka: pierwszy bit można uprościć za pomocą:

for /f "tokens=*" %%q in ('dir /a:d /s /b') do (
    cd "%%q"
    ...
    echo !xsize!
)

Zasadniczo, to zastąpienie użycia findz /a:dopcją (lista katalogów tylko) i /b(używaj gołego formatu, bez nagłówka lub podsumowania). Spowoduje to również usunięcie pliku tymczasowego.


Zmodyfikowana wersja do pracy na folderach z wykrzyknikami w nazwie. Korzystając z odpowiedzi Scotta. Zobacz komentarze poniżej.

Uwaga: REMoznacza to komentarz.

@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

Alternatywą jest użycie programu 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';

Jest to zbyt skomplikowane, aby było możliwie jak najbardziej kompletne - ponadto większość z tych poleceń ma krótsze aliasy; to jest po prostu bardziej czytelne. A jeśli podzielisz niektóre sekcje na funkcje / własną linię, stanie się to znacznie bardziej czytelne i być może krótsze.

Rozbuduj to:

  • Get-ChildItem -Recurse

    Rekurencyjnie wyświetl wszystkie podkatalogi i pliki

  • ?{ $_.PSIsContainer }

    Filtruj, aby zachować tylko katalogi ( ?jest to alias Where-Object). $_odnosi się do obiektów przesłanych do tego potoku - ponieważ Get-ChildItemprzekazuje listę / tablicę obiektów, przetwarza je pojedynczo.

  • %{$_ | Add-Member -MemberType NoteProperty -Name DirSize -Value 0; $_.DirSize = $(Get-ChildItem -Recurse $_.Fullname | ?{ -not $_.PSIsContainer } | Measure-Object -Sum -Property Length).Sum; $_}

    Oblicz rozmiar każdego katalogu ( %jest to alias Foreach-Object, więc uruchom to, co znajduje się pomiędzy { }poszczególnymi obiektami. Każdy obiekt jest katalogiem, jak w poprzednich częściach).

    Rozbuduj to:

    • $_ | Add-Member -MemberType NoteProperty -Name DirSize -Value 0;

      Średnik ( ;) oznacza koniec linii / instrukcji i nie przekazuje danych wyjściowych, w przeciwieństwie do potoku ( |). Ten konkretny bit nie ma danych wyjściowych, a jedynie dodaje DirSizewłaściwość do obiektu katalogu i inicjuje ją na 0. Jest to wykonywane w celu łatwiejszego filtrowania i późniejszego uporządkowania danych wyjściowych.

    • $_.DirSize = $(Get-ChildItem -Recurse $_.Fullname | ?{ -not $_.PSIsContainer } | Measure-Object -Sum -Property Length).Sum;

      Ustaw DirSizena Sumwłaściwość wyniku tego polecenia. $()oznacza wykonanie tego, co jest w nawiasach i zastąpienie tego w.

      Rozbuduj to:

      • Get-ChildItem -Recurse $_.Fullname

        Dostać całą zawartość katalogu bieżącego obiektu ( $_, Fullnamepo prostu oznacza pełną ścieżkę). -Recurseoznacza również policzenie zawartości podkatalogów.

      • ?{ -not $_.PSIsContainer }

        Filtruj, aby zachować tylko pliki. Katalogi mają Lengthwłaściwość 0, więc musimy użyć sumowania plików w środku - zasadniczo tego, co robi twój skrypt wsadowy, z tym wyjątkiem, że mamy do czynienia z rzeczywistymi liczbami, obiektami i właściwościami zamiast chwytania „liczby” jako tekstu find.

      • Measure-Object -Sum -Property Length

        Oblicz sumę wszystkich Lengthprzekazanych do niego właściwości. Zwraca obiekt zawierający właściwość Sum, która jest używana powyżej ( .Sum)

    • $_

    Zasadniczo echoobiekt przenosi go do następnej sekcji. Teraz ma DirSizewłaściwość.

  • Sort-Object DirSize -Descending

    Sortuj malejąco według DirSize

  • Select-Object -First 10 FullName,DirSize

    Wyprowadzaj tylko pierwsze 10, a tylko nazwę i rozmiar

  • Format-Table -AutoSize | Out-String -Width 4096 | Out-File 'sizes.txt';

    Dane wyjściowe do sizes.txt. Format-TableI Out-Stringbity są do zapobiegania obcinania do konsoli szerokości okien (zazwyczaj 80 znaków). 4096 powinien zawierać więcej niż wystarczającą liczbę znaków dla dowolnej ścieżki systemu Windows i rozmiaru katalogu, biorąc pod uwagę, że ścieżka systemu Windows jest zwykle ograniczona do 255 znaków (IIRC). AutoSizeOznacza po prostu zrobić to możliwie jak najkrótszy bez obcinania, zamiast wyściółka z całym mnóstwem spacji aby dopasować 4096 znaków.

I polecenie jako jeden liniowiec do uruchomienia cmd.exe(możesz uruchomić powyższą wersję w programie 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';"
Kok
źródło
Dzięki za szybką wskazówkę. Naprawdę rozwiązało wiele problemów.
Sachin,
„dir / a: d / s / b” ten klient usuwa znaki specjalne ze ścieżki do katalogu. Potrzebuję dokładnej ścieżki. Czy możesz mi pomóc
Sachin
@Sachin Co to za znaki specjalne? Czy możesz podać przykładową ścieżkę, na którą to wpływa?
Bob
oryginalna ścieżka: D: \ Songs \ Audio \ Hindi \ Wake Up S! d i zmieniło się na D: \ Songs \ Audio \ Hindi \ Wake Up Sd
Sachin
@Sachin Ten problem nie wynika z dirpolecenia - twój oryginał zrobiłby to samo. Problem jest z powodu EnableDelayedExpansion. cmdNajpierw analizuje wiersz w pliku wsadowym, aby dowiedzieć się, co powinien zrobić, i zwykle rozszerza zmienne w tym czasie ( %variablename%). Następnie wykonuje linię. EnableDelayedExpansionoznacza rozwinięcie zmiennych w wykrzyknikach ( !variablename!) w czasie wykonywania. Tutaj dzieje się to, że zmienna %%qjest rozwijana w czasie analizy, a następnie cmddusi się !w czasie wykonywania.
Bob