Save values batch file

2019-02-21 00:25发布

I wrote this script to looking for volume with enough free space:

@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
)
)

My problem is that the bytesfree variable dosent save its value. the output is(echo is on)

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

looks like the bytesfree losed its value. Can anyone please help? and provide some explantation? thanks.

2条回答
对你真心纯属浪费
2楼-- · 2019-02-21 00:48

To expand on Joey's (original short) answer, the entire for expression is parsed at once, and the % expansion occurs at parse time. But the value you want isn't there until the DO clause has executed. That is why you need delayed expansion. Read the help on for by typing HELP FOR from the command line.

Based on the comment from your previous question https://stackoverflow.com/a/9096601/1012053, it looks like you are attempting to find the drive with the most free space > 1GB.

Your current code has a slight risk of including the wrong line from the DIR command. I've modified it to filter the output using FINDSTR with a regular expression.

EDIT - Also, the IF command cannot properly compare numbers that exceed 2147483647.

>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

So the numbers need to be 0 prefixed and the IF command must be forced to do a string comparison instead of a numeric comparison. I forced a string comparison by enclosing the 0 prefixed number in quotes.

@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

An alternate method using 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
查看更多
贪生不怕死
3楼-- · 2019-02-21 00:59

Short answer:

Use

setlocal enabledelayedexpansion

instead of just setlocal and then use !bytesfree! to refer to the variable (just replace % by !).


Longer answer:

This is because cmd expands variables as it parses a command, not when the command is run (which, obviously happens after parsing). A command in this case could also be a complete for statement including the block after it. So all instances of %bytesfree% within the loop are replaced by their value before the loop, which happens to be an empty string.

Delayed expansion is a special form of variable expansion which expands variables when a command is run instead of when parsing it. It can be enabled with

setlocal enabledelayedexpansion

(within a batch file) or

cmd /v:on

(for a complete session, but not in a batch file, unless you don't want it to resume).

Then the syntax !bytesfree! is used to refer to variables which are then expanded just prior to running a command. So when setting and using the same variable within a block (for loop, if, etc.) you pretty much always want to use delayed expansion.

查看更多
登录 后发表回答