您的代码存在以下问题:
- 在批处理文件中,
for 元变量前面必须有 两个 %-符号,而不是命令提示符中的一个 (cmd),因此更改 %a 等., 到%%a, 等等;否则会出现语法错误;
- 在使用
for /F 的skip=1 选项时,您可以避免使用findstr /V 过滤掉wmic 输出的标题;
- 我推荐使用
DeviceID,而不是属性Name,根据这个超级用户线程:What is the difference between properties Name, Caption and DeviceID (when executing wmic LogicalDisk)?;
- 不确定您要查询哪些驱动器,但也许您只需要本地磁盘;如果是,则添加子句
where "DriveType=3";参考这篇微软文章:Win32_LogicalDisk class;
- 临时 VBScript 脚本的创建应在调用它的
if 条件内进行,以避免无意义的文件写入活动;
- 您在每次循环迭代中都附加到文本文件,但您从未在开始时初始化一个空文件;也许这是故意的行为,但我不这么认为;无论如何,您可以根据自己的喜好对整个
for /F 循环执行一次重定向,或者(过度)写入 (>) 或附加 (>>);
-
type 命令的管道是无用的,因为type 无论如何都不接受任何传入的数据;我猜| 符号应该已经替换为&;尽管如此,type 命令在循环中没有意义,我认为它应该在循环之后执行,而不是显示一次完整的收集数据;
-
echo( 可以被删除,因为它只是向控制台写入一个空行;
- 最后应清理临时 VBScript 文件;
纠正所有这些事情会导致这样的批处理脚本(为了便于阅读,我没有将它们全部写在一行中):
> "C:\test\test2.txt" (
for /F "skip=1 tokens=1-3" %%a in ('
wmic LogicalDisk where "DriveType=3" get DeviceID^,FreeSpace^,Size
') do @(
if not "%%c"=="" (
> "%TEMP%\tmp.vbs" echo WScript.Echo "%%a" ^& " free=" ^& FormatNumber^(CDbl^(%%b^) / 1024 / 1024 / 1024, 2^) ^& " GiB" ^& " size=" ^& FormatNumber^(CDbl^(%%c^) / 1024 / 1024 / 1024, 2^) ^& " GiB"
CScript //NoLogo "%TEMP%\tmp.vbs"
)
)
)
type "C:\test\test2.txt"
del "%TEMP%\tmp.vbs"
不过,整个方法还可以改进:
- 临时 VBScript 脚本可以编写一次,而不是每次
for /F 循环迭代;为此,您需要将变量值作为命令行参数传递;请参阅此线程以了解其工作原理:Using command line arguments in VBscript;
- 使用
echo 编写临时VBScript 文件需要大量转义,例如^&;为了避免这种情况,我们可以将 VBScript 代码放在一个以 :::: 为前缀的块中,这被批处理文件解释器视为无效的跳转标签,甚至可以通过在它们之前放置 exit /B 来跳过它们; findstr可以轻松提取这个块,for /F可以去掉冒号;
这就是我的意思:
> "%TEMP%\tmp.vbs" (for /F "tokens=* delims=:" %%z in ('findstr /B "::::" "%~f0"') do @echo/%%z)
> "C:\test\test2.txt" (
for /F "skip=1 tokens=1-3" %%a in ('
wmic LogicalDisk where "DriveType=3" get DeviceID^,FreeSpace^,Size
') do @(
if not "%%c"=="" CScript //NoLogo "%TEMP%\tmp.vbs" "%%a" "%%b" "%%c"
)
)
type "C:\test\test2.txt"
del "%TEMP%\tmp.vbs"
exit /B
::::If WScript.Arguments.Count < 3 Then WScript.Quit 1
::::WScript.Echo WScript.Arguments.Item(0) & _
:::: " free=" & FormatNumber(CDbl(WScript.Arguments.Item(1)) / 1024 / 1024 / 1024, 2) & " GiB" & _
:::: " size=" & FormatNumber(CDbl(WScript.Arguments.Item(2)) / 1024 / 1024 / 1024, 2) & " GiB"
在应用此线程中演示的技术时,您甚至可以避免使用包含 VBScript 代码的临时文件:Is it possible to embed and execute VBScript within a batch file without using a temporary file?
(另请参阅这些 Microsoft 文章:Using Windows Script Files (.wsf) 和 How Come You Guys Don’t Use .WSF Files?。)
<!-- :Batch script section
> "C:\test\test2.txt" (
for /F "skip=1 tokens=1-3" %%a in ('
wmic LogicalDisk where "DriveType=3" get DeviceID^,FreeSpace^,Size
') do @(
if not "%%c"=="" CScript //NoLogo "%~f0?.wsf" "%%a" "%%b" "%%c"
)
)
type "C:\test\test2.txt"
exit /B
---- WSF script section -->
<job><script language="VBScript">
If WScript.Arguments.Count < 3 Then WScript.Quit 1
WScript.Echo WScript.Arguments.Item(0) & _
" free=" & FormatNumber(CDbl(WScript.Arguments.Item(1)) / 1024 / 1024 / 1024, 2) & " GiB" & _
" size=" & FormatNumber(CDbl(WScript.Arguments.Item(2)) / 1024 / 1024 / 1024, 2) & " GiB"
</script></job>
这里还有另一种不使用临时 VBScript 文件的方法,应用此线程中说明的方法:HTA & Batch Hybrid, passing variables from BATCH section。这样做的缺点是 HTA 窗口出现和消失的短暂闪烁。
(另请参阅这篇 Microsoft 文章:HTML Applications (HTAs)。)
<!-- ::Batch script section ----
> "C:\test\test2.txt" (
for /F "skip=1 tokens=1-3" %%a in ('
wmic LogicalDisk where "DriveType=3" get DeviceID^,FreeSpace^,Size
') do @(
if not "%%c"=="" set "DeviceID=%%a" & set "FreeSpace=%%b" & set "Size=%%c" & MSHTA "%~f0"
)
)
type "C:\test\test2.txt"
exit /B
---- ::HTA script section -->
<script language="VBScript">
Set Env = CreateObject("WScript.Shell").Environment("Process")
Set StdOut = CreateObject("Scripting.FileSystemObject").GetStandardStream(1)
If Not Env("DeviceID") = "" Then
StdOut.WriteLine(Env("DeviceID") & _
" free=" & FormatNumber(CDbl(Env("FreeSpace")) / 1024 / 1024 / 1024, 2) & " GiB" & _
" size=" & FormatNumber(CDbl(Env("Size")) / 1024 / 1024 / 1024, 2) & " GiB")
End If
Set StdOut = Nothing
Set Env = Nothing
Close()
</script>