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
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
Use
setlocal enabledelayedexpansion
instead of just setlocal
and then use !bytesfree!
to refer to the variable (just replace %
by !
).
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.