批处理:延迟参数的回显后不需要的换行符



这是使用wmic.exe打印包含不同系统信息的文本的批处理的一部分。在一个部分中,我使用调用和标签为硬盘信息创建自动参数,我必须使用参数中的参数才能使其工作。这只适用于启用延迟扩展的情况。因此,在包含回显到文件的代码的for/f循环中,正在回显并有延迟扩展的行直接在扩展结束后回显换行符!我不知道为什么,也不知道该怎么做。我已经下定决心用批处理来做这件事,是的,我知道在vbs脚本中用wmi更容易做到这一点。任何帮助都与有关

@echo off
for /f "skip=2 delims=" %%a in ('wmic diskdrive get medialoaded') do call :getdisk
for /f "skip=2 delims=" %%a in ('wmic diskdrive get medialoaded') do call :setdisk
>%tmp%t.x echo wscript.echo round^(wscript.arguments^(0^) / ^(1024 * 1024 * 1024^), 1^)
for /f "skip=2 delims=" %%a in ('wmic diskdrive get medialoaded') do call :numdisk
goto:eof
:getdisk
set /a disk=%disk%+1
goto:eof
:setdisk
if not defined numreset set /a numreset=%disk%-1
if not defined num (set num=0) else (set /a num=%num%+1)
for /f "tokens=1-10 delims==" %%a in ('wmic diskdrive %num% get interfacetype^,model^,size /format:list') do set %%a%num%=%%b
if "%num%"=="%numreset%" set "num="
goto:eof
:numdisk
if not defined num (set num=0) else (set /a num=%num%+1)
set /a hdd=%num%+1
setlocal enabledelayedexpansion
set interfacetype=interfacetype%num%
set mediatype=mediatype%num%
set size=size%num%
if "%disk%" geq "%num%" >>hdd.txt echo HDD %hdd%:      index %num%
if "%disk%" geq "%num%" >>hdd.txt echo InterFace:  !%interfacetype%!
if "%disk%" geq "%num%" >>hdd.txt echo MediaType:  !%mediatype%!
if "%disk%" geq "%num%" for /f %%a in ('cscript //nologo //e:vbscript %tmp%t.x "!%size%!"') do set sizegb=%%a
if "%disk%" geq "%num%" >>hdd.txt echo Size:       !%size%! b ^(%sizegb% gb^)
if "%disk%" geq "%num%" >>hdd.txt echo.
endlocal
goto:eof

解决方法

由于换行符在扩展变量内,因此很容易将其删除:

::before:
!%var%!
::after:
!%var%:~0,-1!

天哪!这段代码极其复杂,效率低下——我几乎无法理解其中的逻辑。让它发挥作用给你更多的力量,但我想我可以向你展示一个更好的方法:)

首先,它不是额外的换行符或换行符(<LF>,十六进制0x0A,十进制10),而是额外的回车符(<CR>,十六进制0x00D,十进制13)。不需要的字符是FOR/F如何与WMIC的unicode输出交互的一个奇怪的工件。FOR/F试图将unicode转换为ANSI,但不知何故用<CR><CR><LF>终止了每一行输出。FOR/F在<LF>之前结束每一行,然后如果最后一个字符恰好是<CR>,则去掉它,从而在每一行的末尾留下一个不需要的尾随<CR>

消除不需要的字符的一个万无一失的方法是使用额外的FOR/F,因为如果最后一个字符是<CR>:,它会去掉它

for /f "delims=" %%A in ('WMIC ...') do for /f "yourOptions" %%B in ("%%A") do ...

这种方法的好处是它不需要延迟扩展。

但是,由于您已经在使用延迟扩展,因此设置变量然后使用子字符串操作修剪最后一个字符的方法非常好。


现在开发一个更合理的代码库来获得您想要的结果:

不需要多次解析WMIC输出——您可以在只执行一次WMIC的单个FOR/F循环中完成所有操作。

您可以使用CSV而不是LIST格式。这将磁盘驱动器所需的所有值放在一行中,以逗号分隔。唯一的缺点是可能存在空值,这会导致FOR/F解析出现问题,连续的分隔符被视为一个分隔符,因此可能会丢失令牌。诀窍是使用搜索和替换在每个令牌周围加引号。然后,一个缺失的值变成,"",,它可以很容易地被第二个FOR/F解析。稍后使用%%~A从每个标记中去掉引号。

您的WMIC命令将获取未使用的Model,而您的输出将引用未获取的Media Type。我修复了获取和输出这两者的代码。

您为每个磁盘索引运行不同的WMIC,但WMIC DISKDRIVE提供了一个您可以获得的index值,所以为什么不使用它呢?我的输出没有按索引顺序排序,但所有信息都在那里。如果真的需要,可以添加额外的代码来按索引对结果进行排序。

将外部FOR/F括在括号内,然后只重定向一次输出,这样更有效。

最后,不需要临时的VBS脚本来计算。相反,在批处理脚本中嵌入和调用JScript是很容易的。

@if (@X)==(@Y) @end /* harmless hybrid line that begins a JScrpt comment
::************ Batch portion ***********
@echo off
setlocal enableDelayedExpansion
set cnt=0
(
  for /f "skip=2 delims=" %%A in (
    '"wmic diskdrive get interfacetype,model,size,index,mediaType /format:csv"'
  ) do (
    set "ln=%%A"
    set "ln=!ln:~0,-1!"
    set "ln="!ln:,=","!""
    set /a cnt+=1
    for /f "tokens=2-6 delims=," %%B in ("!ln!") do (
      echo HDD !cnt!: Index %%~B
      echo Interface: %%~C
      echo Model: %%~E
      echo Media: %%~D
      set "size="
      if %%F neq "" for /f %%N in (
        'cscript //E:JScript //nologo "%~f0" "Math.round(%%~F/1024/1024/1024*10)/10"'
      ) do set "size=%%N GiB"
      echo  Size: !size!
      echo(
    )
  )
)>hdd.txt
exit /b
************ JScript portion ***********/
WScript.StdOut.WriteLine(eval(WScript.Arguments.Unnamed(0)));

EDIT:我刚刚意识到模型描述可能包含逗号,这会导致FOR/F解析CSV格式时出现问题。因此,这里有另一个恢复为List格式的解决方案。事实证明,代码甚至更简单:)

我使用第二个FOR/F技巧来删除不需要的尾部<CR>

@if (@X)==(@Y) @end /* harmless hybrid line that begins a JScrpt comment
::************ Batch portion ***********
@echo off
setlocal enableDelayedExpansion
set cnt=0
(
  for /f "delims=" %%L in (
    '"wmic diskdrive get interfaceType,model,size,index,mediaType /format:list"'
  ) do for /f "tokens=1* delims==" %%A in ("%%L") do (
    if %%A equ Index (
      if !cnt! gtr 0 echo(
      set /a cnt+=1
      echo HDD !cnt!: Index %%B
    ) else if %%A equ Size (
      set "size="
      if "%%B" neq "" for /f %%N in (
        'cscript //E:JScript //nologo "%~f0" "Math.round(%%B/1024/1024/1024*10)/10"'
      ) do set "size=%%N GiB"
      echo %%A: !size!
    ) else echo %%A: %%B
  )
)>hdd.txt
exit /b
************ JScript portion ***********/
WScript.StdOut.WriteLine(eval(WScript.Arguments.Unnamed(0)));