我正在尝试编写一个批处理脚本,该脚本可以获取(除其他外)计算机所有磁盘驱动器的列表。基本代码如下所示:
REM Build the list of disk drives to monitor
SETLOCAL enabledelayedexpansion
FOR /f "skip=1 tokens=1 delims=:" %%a in ('"WMIC logicaldisk WHERE drivetype=3 GET deviceid"') do (
SET "DISK_DATABASES=!DISK_DATABASES!%%a|"
SET "DRIVES_TO_MONITOR=!DRIVES_TO_MONITOR!%%a:\\|"
)
我显然构建了两个格式略有不同的列表供以后使用。然而,当我运行它时,我得到的输出看起来像这样:
C|D|E||
C:\\|D:\\|E:\\|:\\|
现在,我希望两种情况下的尾随管道都可以管理,但我真的很困惑为什么还有一个额外的空白条目。如果我手动运行wmic
命令,我可以看到输出结尾确实有一个空行,但我的理解是/f
特别应该忽略空行。
如果我打开ECHO
,看起来最后一行只是作为回车/换行符或类似物进入。有没有办法做我期待的事情?我错过了什么吗?我试图在循环中写一个if
条件来排除最后一行,但它是......时髦而且从未奏效。我感谢任何/所有的帮助。
答案 0 :(得分:11)
我刚刚谈到这个话题。我一直在使用findstr / v来排除空行:
FOR /f "usebackq skip=1 tokens=1 delims=:" %%a in (`WMIC logicaldisk WHERE "drivetype=3" GET deviceid ^| findstr /v /r "^$"`) do (
答案 1 :(得分:5)
在这种情况下,最后一次迭代不会产生空项目,只有C|D|E||
才会得到echo %DISK_DATABASES%
的输出,
但是echo !DISK_DATABASES!
会输出||D|E|
??
那是因为最后一个元素是一个<CR>
个字符
并且在扩展百分比之后直接删除<CR>
个字符,但不会延迟扩展。
你可以避免这种情况,使用百分比扩展来删除它们
setlocal EnableDelayedExpansion
FOR /f "skip=1 tokens=1 delims=:" %%a in ('"WMIC logicaldisk WHERE drivetype=3 GET deviceid"') do (
set "item=%%a"
call :removeCR
if not "!item!"=="" (
SET "DISK_DATABASES=!DISK_DATABASES!!item!|"
SET "DRIVES_TO_MONITOR=!DRIVES_TO_MONITOR!!item!:\\|"
)
)
goto :eof
:removeCR
:removeCR
set "Item=%Item%"
exit /b
答案 2 :(得分:4)
根据http://ss64.com/nt/for_f.html
许多较新的命令和实用程序(例如WMIC)以unicode格式输出文本文件,这些文件无法通过需要ASCII的FOR命令读取。 要转换文件格式,请使用TYPE命令。
因此,WMIC和FOR似乎不能很好地协同发作。
答案 3 :(得分:3)
我发现了一种更有效,更可靠的方法,可以从每行末尾删除不需要的<CR>
。没有临时文件,也不需要CALL。
我不明白FOR / F如何将WMIC unicode输出转换为ASCII的机制。通常FOR / F无法读取unicode。但无论如何,每个转换的行都以<CR><CR><LF>
结尾。 FOR / F会在每个<LF>
处打破行,然后如果该行中的最后一个字符为<CR>
,则会删除最后一个<CR>
,在这种情况下会留下不需要的<CR>
解决方案是简单地将每一行传递给另一个FOR / F: - )
@echo off
setlocal enableDelayedExpansion
for /f "skip=1 delims=" %%A in (
'wmic logicaldisk where "drivetype=3" get deviceid'
) do for /f "tokens=1 delims=:" %%B in ("%%A") do (
set "disk_databases=!disk_databases!%%B|"
set "drives_to_monitor=!drives_to_monitor!%%B:\\|"
)
此方法比使用常规扩展更可靠,因为您不必担心引用或转义特殊字符。例如,使用常规扩展的CALL方法无法处理像"this & that" & the other
这样的字符串。但是这种方法没有问题。
答案 4 :(得分:0)
我处理这个问题的标准习惯是将WMIC的输出写入临时文件,然后使用TYPE(将UTF16缩减为ASCII)将其输入FOR,如下所示:
:: Standard environment setup
setlocal enabledelayedexpansion
:: Every variable whose name starts with "tf" will identify a temporary
:: file - remove any such variables inherited from the parent environment
for /f %%V in ('set tf') do set %%V=
:: Create some temporary filenames. Prefix all of them with this script's
:: own name to avoid clashes with those owned by other scripts.
for /l %%I in (1,1,4) set tf%%I="%temp%\%~n0-temp%%I.txt"
:: Use temp file to work around coding mismatch between WMIC out and FOR in
wmic product where "name like 'Microsoft Office %% 2010'" get packagecache >!tf1!
for /f "skip=1" %%P in ('type !tf1!') do if exist "%%~P" msiexec /x "%%~P" /passive /norestart
:: Before quitting script, clean up temporary files
for /f %%V in ('set tf') do if exist "%%~V" del /f /q "%%~V"
endlocal
答案 5 :(得分:0)
运行以下命令:
wmic blah /value | find "=" >> wherever
输出将是:
field=value
请注意,不会有额外的行。
答案 6 :(得分:0)
添加^| findstr .
,您将只获得空行
REM Build the list of disk drives to monitor SETLOCAL enabledelayedexpansion FOR /f "skip=1 tokens=1 delims=:" %%a in ( '"WMIC logicaldisk WHERE drivetype=3 GET deviceid" ^| findstr .') do ( SET "DISK_DATABASES=!DISK_DATABASES!%%a|" SET "DRIVES_TO_MONITOR=!DRIVES_TO_MONITOR!%%a:\|" )