Пакетный файл сохранения значений

Я написал этот скрипт для поиска тома с достаточным количеством свободного места:

@echo on
setlocal
set gbsize=1,073,741,824
Set gbsize=%gbsize:,=%

for %%A in (A B C D) do ( 
for /f "tokens=3,4,5,*" %%B in ('dir %%A:\') do (
set bytesfree=%%B
set bytesfree=%bytesfree:,=%
if %%D == free If %bytesfree% gtr %gbsize% echo hi
)
)

Моя проблема в том, что переменная bytesfree не сохраняет свое значение. выход (эхо включено)

C:\Users\Desktop>(
set bytesfree=**780,607,488**
 set bytesfree=**23167987712**
 if free == free If 23167987712 GTR 1073741824 echo hi
)
hi

похоже, что bytesfree потерял свое значение. Кто-нибудь может помочь? и предоставить некоторые пояснения? Спасибо.


person RRR    schedule 01.02.2012    source источник


Ответы (2)


Короткий ответ:

Использовать

setlocal enabledelayedexpansion

вместо просто setlocal, а затем используйте !bytesfree! для ссылки на переменную (просто замените % на !).


Более длинный ответ:

Это связано с тем, что cmd расширяет переменные при анализе команды, а не при ее запуске (что, очевидно, происходит после анализа). команда в этом случае также может быть полным for оператором, включая блок после него. Таким образом, все экземпляры %bytesfree% внутри цикла заменяются их значением перед циклом, которое оказывается пустой строкой.

Отложенное расширение — это особая форма расширения переменных, которая расширяет переменные при запуске команды, а не при ее анализе. Его можно включить с помощью

setlocal enabledelayedexpansion

(в пакетном файле) или

cmd /v:on

(для всего сеанса, но не в пакетном файле, если вы не хотите, чтобы он возобновлялся).

Затем синтаксис !bytesfree! используется для ссылки на переменные, которые затем раскрываются непосредственно перед запуском команды. Таким образом, при настройке и использовании одной и той же переменной внутри блока (цикл for, if и т. д.) практически всегда требуется использовать отложенное раскрытие.

person Joey    schedule 01.02.2012

Чтобы расширить ответ Джоуи (исходный короткий), все выражение for анализируется сразу, а расширение% происходит во время анализа. Но нужного вам значения нет, пока не будет выполнено предложение DO. Вот почему вам нужно отсроченное расширение. Прочтите справку по for, набрав HELP FOR в командной строке.

Основываясь на комментарии к вашему предыдущему вопросу https://stackoverflow.com/a/9096601/1012053, похоже, что вы пытаются найти диск с наибольшим объемом свободного места > 1 ГБ.

Ваш текущий код имеет небольшой риск включения неправильной строки из команды DIR. Я изменил его для фильтрации вывода с помощью FINDSTR с регулярным выражением.

EDIT. Кроме того, команда IF не может корректно сравнивать числа, превышающие 2 147 483 647.

>if 2147483647 gtr 2147483646 echo greater
greater

>if 2147483648 gtr 2147483647 echo greater

>if 1000000000000 gtr 2147483647 echo greater

>if 2147483648 equ 2147483647 echo equal
equal

>if 1000000000000 equ 2147483647 echo equal
equal

Таким образом, числа должны иметь префикс 0, а команда IF должна выполнять сравнение строк вместо числового сравнения. Я заставил сравнение строк, заключив число с префиксом 0 в кавычки.

@echo off
setlocal enableDelayedExpansion
set "gbsize=1,073,741,824"
set "gbsize=%gbsize:,=%"
set "maxfree=000000000000000"
set "maxdrive="
for %%A in (C D) do (
  for /f "tokens=3" %%B in ('dir %%A:\^|findstr /r /c:"^ *.* *Dir(s).*bytes free$"') do (
    set "bytesfree=000000000000000%%B"
    set "bytesfree=!bytesfree:,=!"
    set "bytesfree=!bytesfree:~-15!"
    if "!bytesfree!" gtr "!maxfree!" (
      set "maxfree=!bytesfree!"
      set "maxdrive=%%A:"
    )
  )
)
for /f "tokens=* delims=0" %%A in ("%maxfree%") do set maxfree=%%A
echo Drive with max free space is %maxdrive%  %maxfree% bytes free
if %maxfree% gtr %gbsize% echo That is more than 1GB

Альтернативный метод с использованием WMIC

@echo off
setlocal enableDelayedExpansion
set "gbsize=1,073,741,824"
set "gbsize=%gbsize:,=%"
set "maxfree=000000000000000"
set "maxdrive="
for /f "skip=1 tokens=1,2" %%A in ('wmic volume get DriveLetter^, FreeSpace') do (
  if "%%B" neq "" (
    set "bytesfree=000000000000000%%B"
    set "bytesfree=!bytesfree:~-15!"
    if "!bytesfree!" gtr "!maxfree!" (
      set "maxfree=!bytesfree!"
      set "maxdrive=%%A"
    )
  )
)
for /f "tokens=* delims=0" %%A in ("%maxfree%") do set maxfree=%%A
echo Drive with max free space is %maxdrive%  %maxfree% bytes free
if %maxfree% gtr %gbsize% echo That is more than 1GB
person dbenham    schedule 01.02.2012
comment
спасибо, ваш комментарий о IF мне очень помог! Я не могу использовать wmic или findstr, так как я использую winpe, в котором нет этих команд. - person RRR; 02.02.2012
comment
Я попробовал ваше предложение сравнить строки, и оно работает хорошо, во-первых, спасибо, а также не могли бы вы объяснить, как это работает? почему вы устанавливаете maxsize равным 00000000000000000? заранее спасибо - person RRR; 02.02.2012
comment
Сначала я добавляю к числу нули, а затем оставляю самые правые 15 цифр. Это гарантирует, что все числа имеют фиксированную ширину, поэтому вы правильно сортируете их как строки. Пакет Windows может обрабатывать только числа до 2 ГБ. Теперь доступны дисковые накопители, которые могут хранить терабайты (ТБ). Поэтому я произвольно выбрал ~ 999 ТБ в качестве максимума, что составляет 15 цифр. Если диски становятся больше, то количество цифр должно увеличиваться. - person dbenham; 02.02.2012