【问题标题】:batch: unwanted newline character after echo of a delayed parameter批处理:延迟参数回显后不需要的换行符
【发布时间】:2014-04-17 15:33:33
【问题描述】:

这是使用 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!

【问题讨论】:

  • 这可能会有所帮助:stackoverflow.com/a/23067935/2152082
  • 它帮助我了解了一些我不知道的 wmic 命令。我会用其他地方。谢谢。但我的问题中的问题是由其他原因引起的。当编号参数首次设置在 ':setdisk' 标签下时,没有额外的换行符或来自 wmic 的其他数据设置给它们。在 !%variable%! 的扩展过程中添加了换行符在文件的回声中。
  • 更正:换行符确实在扩展变量的内部。毕竟你可能正在做某事!但是当我在本地内存之外回显并启用延迟扩展为 %variable% 时,新行没有被回显注册..

标签: windows batch-file


【解决方案1】:

天哪!该代码极其复杂且效率低下——我几乎无法遵循逻辑。为您提供更多功能以使其正常工作,但我想我可以向您展示更好的方法:)

首先,它不是一个额外的换行符或换行符(<LF>,十六进制 0x0A,十进制 10),它是一个额外的回车(<CR>,十六进制 0x0D,十进制 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 命令获取了您不使用的模型,并且您的输出引用了您没有获取的媒体类型。我修复了获取和输出两者的代码。

您为每个磁盘索引运行不同的 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)));

编辑:我刚刚意识到模型描述可能包含逗号,这会导致 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)));

【讨论】:

  • aah,大师来了:) 是的,我承认我的方法是.. 非正统呵呵。相信我,我已经绕过了十倍不同的方式。包含上述代码的批处理也将 wmic 用于许多其他东西,并且有一次我不得不使用 vbs 脚本来获取处理器套接字,因为我似乎无法在 wmic 中找到它。但从长远来看,混合解决方案要好得多!我会实施它。至于将 csv 格式与 wmic 一起使用 .. 我真的尝试过,但总是得到“无效的 XSL 格式(或)文件名”。尝试的时候。您的上述示例中也出现了同样的错误!有什么想法吗?
  • 我只是补充说我已经尝试过:stackoverflow.com/questions/9673057/…
  • 哎呀,我错过了一些括号,现在它可以工作了:) 谢谢你的解决方案戴夫。我会将此标记为答案,因为它解决了我的所有问题
  • @Profess0r1011000 - 我刚刚意识到模型描述中的逗号会导致解析 CSV 格式的问题。我添加了第二个解决方案,可以恢复为 LIST 格式。
  • 就在我重写整个批次的十行时:P 好吧,我想这仅适用于值中实际上可能有逗号的地方。所以我想我会再过一遍,并对我不确定的值进行一些更改。感谢您将此添加到您的答案中!
猜你喜欢
  • 1970-01-01
  • 2017-05-21
  • 2012-08-10
  • 2011-10-29
  • 2015-08-01
  • 1970-01-01
相关资源
最近更新 更多