如何删除批处理文件中的新行?

How to remove new lines in batch file?

我正在处理批处理文件并导出到文本文件。似乎所有这些都可以,但是当我打开文本文件时,许多新行都会中断。所以,我想删除它们。

@echo OFF
setlocal EnableDelayedExpansion
(
  systeminfo |findstr /c:"Host Name" /c:"OS Name" /c:"OS Version" /c:"Original Install Date" /c:"System Manufacturer" /c:"System Model" /c:"System Type" /c:"Total Physical Memory"
    wmic bios get serialnumber /Format:list | more | findstr .
    wmic cpu get name /Format:list | more | findstr .
  echo=%userdomain%\%username%
)> %ComputerName%.txt

结果文本文件没问题,但仍有许多新行中断,我想删除它们

Host Name:                 PGV-PF165HNN
OS Name:                   Microsoft Windows 10 Pro
OS Version:                10.0.18363 N/A Build 18363
Original Install Date:     7/22/2019, 6:28:01 PM
System Manufacturer:       LENOVO
System Model:              20JM0009US
System Type:               x64-based PC
BIOS Version:              LENOVO N1QET87W (1.62 ), 2/27/2020
Total Physical Memory:     8,072 MB
SerialNumber=PF165HNN

Name=Intel(R) Core(TM) i5-6300U CPU @ 2.40GHz

WINDOM1\brian.lee

只是不使用 DisableDelayedExpansion 的替代方法:

@echo off && setlocal EnableDelayedExpansion

set "_usrd=Domain\User Name:          !USERDOMAIN!\!USERNAME!" && set "_bios=Bios Serial Number:       -x" && set "_CPUs=CPU Name:                 -y"
set "_wmic=%SystemRoot%\System32\wbem\wmic.exe" && pushd "%SystemRoot%\System32" && >"%temp%\%ComputerName%.txt" 2>nul (
systeminfo.exe | findstr "Host.Name OS.Name OS.Version Original.Install.Date System.Manufacturer System.Model System.Type Total.Physical.Memory"
for /f skip^=1^tokens^=* %%i in ('!_wmic! bios get serialnumber^|findstr "[0-9] [aZ]"')do ^< nul call set /p "'=!_bios:-x= %%~i!" <nul & echo\
for /f skip^=1^tokens^=* %%j in ('!_wmic! cpu get name^|findstr "[0-9] [aZ]"')do ^< nul call set /p "'=!_CPUs:-y= %%~j!" <nul & echo\
echo\!_usrd! ) && type "%temp%\%ComputerName%.txt" && popd && endlocal && goto :EOF 
  • 输出:
Host Name:                 LAME_SLUG
OS Name:                   Microsoft Windows 10 Pro
OS Version:                10.0.18363 N/A Build 18363
Original Install Date:     3/27/2020, 11:17:06 PM
System Manufacturer:       LENOVO
System Model:              80YH
System Type:               x64-based PC
BIOS Version:              LENOVO 4WCN46WW, 12/30/2019
Total Physical Memory:     16,259 MB
Bios Serial Number:        PE03A187
CPU Name:                  Intel(R) Core(TM) i7-7500U CPU @ 2.70GHz
Domain\User Name:          LAME_SLUG\ecker

%SystemRoot%\System32\systeminfo.exe 的 OS 语言相关输出是 character encoded in ASCII/ANSI/OEM which means one byte per character using the code page as displayed on running in a command prompt window chcp. The code page depends on the country (region) configured for the account used to run the batch file. The code page does not really matter as long as the data of interest do not contain characters with a code value greater 127 (non-ASCII 个字符)。

findstr过滤的systeminfo的输出是二进制的,文件中的十六进制偏移量留给冒号,字节的十六进制值,以及它们在分号后的ASCII表示:

0000h: 48 6F 73 74 20 4E 61 6D 65 3A 20 20 20 20 20 20 ; Host Name:      
0010h: 20 20 20 20 20 20 20 20 20 20 20 50 47 56 2D 50 ;            PGV-P
0020h: 46 31 36 35 48 4E 4E 0D 0A 4F 53 20 4E 61 6D 65 ; F165HNN..OS Name
0030h: 3A 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ; :               
0040h: 20 20 20 20 4D 69 63 72 6F 73 6F 66 74 20 57 69 ;     Microsoft Wi
0050h: 6E 64 6F 77 73 20 31 30 20 50 72 6F 0D 0A 4F 53 ; ndows 10 Pro..OS
0060h: 20 56 65 72 73 69 6F 6E 3A 20 20 20 20 20 20 20 ;  Version:       
0070h: 20 20 20 20 20 20 20 20 20 31 30 2E 30 2E 31 38 ;          10.0.18
0080h: 33 36 33 20 4E 2F 41 20 42 75 69 6C 64 20 31 38 ; 363 N/A Build 18
0090h: 33 36 33 0D 0A 4F 72 69 67 69 6E 61 6C 20 49 6E ; 363..Original In
00a0h: 73 74 61 6C 6C 20 44 61 74 65 3A 20 20 20 20 20 ; stall Date:     
00b0h: 37 2F 32 32 2F 32 30 31 39 2C 20 36 3A 32 38 3A ; 7/22/2019, 6:28:
00c0h: 30 31 20 50 4D 0D 0A 53 79 73 74 65 6D 20 4D 61 ; 01 PM..System Ma
00d0h: 6E 75 66 61 63 74 75 72 65 72 3A 20 20 20 20 20 ; nufacturer:     
00e0h: 20 20 4C 45 4E 4F 56 4F 0D 0A 53 79 73 74 65 6D ;   LENOVO..System
00f0h: 20 4D 6F 64 65 6C 3A 20 20 20 20 20 20 20 20 20 ;  Model:         
0100h: 20 20 20 20 20 32 30 4A 4D 30 30 30 39 55 53 0D ;      20JM0009US.
0110h: 0A 53 79 73 74 65 6D 20 54 79 70 65 3A 20 20 20 ; .System Type:   
0120h: 20 20 20 20 20 20 20 20 20 20 20 20 78 36 34 2D ;             x64-
0130h: 62 61 73 65 64 20 50 43 0D 0A 42 49 4F 53 20 56 ; based PC..BIOS V
0140h: 65 72 73 69 6F 6E 3A 20 20 20 20 20 20 20 20 20 ; ersion:         
0150h: 20 20 20 20 20 4C 45 4E 4F 56 4F 20 4E 31 51 45 ;      LENOVO N1QE
0160h: 54 38 37 57 20 28 31 2E 36 32 20 29 2C 20 32 2F ; T87W (1.62 ), 2/
0170h: 32 37 2F 32 30 32 30 0D 0A 54 6F 74 61 6C 20 50 ; 27/2020..Total P
0180h: 68 79 73 69 63 61 6C 20 4D 65 6D 6F 72 79 3A 20 ; hysical Memory: 
0190h: 20 20 20 20 38 2C 30 37 32 20 4D 42 0D 0A       ;     8,072 MB..

%SystemRoot%\System32\wbem\wmic.exe 的输出总是 Unicode encoded using UTF-16 Little Endian encoding with byte order mark (BOM)。因此,两个使用的 wmic 命令行的输出是每个字符两个字节。

命令行wmic bios get serialnumber /Format:list以二进制形式产生输出:

0000h: FF FE 0D 00 0A 00 0D 00 0A 00 53 00 65 00 72 00 ; ÿþ........S.e.r.
0010h: 69 00 61 00 6C 00 4E 00 75 00 6D 00 62 00 65 00 ; i.a.l.N.u.m.b.e.
0020h: 72 00 3D 00 50 00 46 00 31 00 36 00 35 00 48 00 ; r.=.P.F.1.6.5.H.
0030h: 4E 00 4E 00 0D 00 0A 00 0D 00 0A 00 0D 00 0A 00 ; N.N.............

前两个字节FF FE是UTF-16 Little Endian的字节顺序标记。每个 ASCII 字符由两个字节(16 位)编码,高字节的值为 0。换行符为回车符 return(0D 00)和换行符(0A 00)。首先输出两个空行,然后是包含感兴趣数据的行,最后再输出两个空行。

命令行wmic cpu get name产生二进制输出:

0000h: FF FE 0D 00 0A 00 0D 00 0A 00 4E 00 61 00 6D 00 ; ÿþ........N.a.m.
0010h: 65 00 3D 00 49 00 6E 00 74 00 65 00 6C 00 28 00 ; e.=.I.n.t.e.l.(.
0020h: 52 00 29 00 20 00 43 00 6F 00 72 00 65 00 28 00 ; R.). .C.o.r.e.(.
0030h: 54 00 4D 00 29 00 20 00 69 00 35 00 2D 00 36 00 ; T.M.). .i.5.-.6.
0040h: 33 00 30 00 30 00 55 00 20 00 43 00 50 00 55 00 ; 3.0.0.U. .C.P.U.
0050h: 20 00 40 00 20 00 32 00 2E 00 34 00 30 00 47 00 ;  .@. .2...4.0.G.
0060h: 48 00 7A 00 0D 00 0A 00 0D 00 0A 00 0D 00 0A 00 ; H.z.............

Unicode 输出被 cmd.exe 重定向到 more 处理批处理文件,现在输出的行每个字符一个字节。但是 Windows 命令处理器在解释 UTF-16 LE 编码行时有一个错误,可以在使用以下命令行时看到:

wmic bios get serialnumber /Format:list | more >output.txt

文件 output.txt 包含二进制字节:

0000h: 0D 0D 0A 0D 0D 0A 53 65 72 69 61 6C 4E 75 6D 62 ; ......SerialNumb
0010h: 65 72 3D 50 46 31 36 35 48 4E 4E 0D 0D 0A 0D 0D ; er=PF165HNN.....
0020h: 0A 0D 0D 0A 0D 0A 0D 0A                         ; ........

每个 Unicode 编码的回车 return + 换行符 (0D 00 0A 00) 变成 ASCII 编码的回车 return + 回车 return + 换行 (0D 0D 0A)。

这才是真正的问题所在。额外的回车 return 导致使用正则表达式搜索字符串 . 匹配所有具有至少一个字符的行,空行也被此正则表达式搜索字符串匹配,输出从 Unicode 转换为不正确ASCII.

这取决于使用的文本编辑器如何解释无效的换行符序列。大多数文本编辑器将不带换行符的回车符 return 解释为换行符,但 findstr 不会那样做。

一种解决方案是明确搜索包含感兴趣数据的行。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
(
    %SystemRoot%\System32\systeminfo.exe | %SystemRoot%\System32\findstr.exe /L /C:"Host Name" /C:"OS Name" /C:"OS Version" /C:"Original Install Date" /C:"System Manufacturer" /C:"System Model" /C:"System Type" /C:"Total Physical Memory"
    %SystemRoot%\System32\wbem\wmic.exe BIOS GET SerialNumber /VALUE | %SystemRoot%\System32\findstr.exe /L /C:SerialNumber
    %SystemRoot%\System32\wbem\wmic.exe CPU GET Name /VALUE | %SystemRoot%\System32\findstr.exe /L /C:Name
    echo %USERDOMAIN%\%USERNAME%
) >"%ComputerName%.txt"
endlocal

写入文件 %ComputerName%.txt 的数据完全用 ASCII 编码,所有地方都只使用 0D 0A 作为行终止符。

关于代码小改动的一些附加信息:

  1. 命令 more 被省略,因为不是真正必要的。 Windows 命令处理器 cmd.exe.
  2. 完成了从 Unicode 到 ASCII 的不正确转换
  3. Delayed environment variable expansion 根本不需要此批处理文件启用。
  4. 所有可执行文件都指定了众所周知的完整限定文件名。因此 cmd.exe 不必使用环境变量 PATHEXTPATH.
  5. 的值搜索可执行文件
  6. WMIC 选项 /Format:list 被选项 /VALUE 替换,结果相同。
  7. FINDSTR 是 运行,带有选项 /L 以明确指示 findstr 到 运行 文字搜索,尽管这是默认使用选项 /C:.

更好的批处理文件代码是:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
(
    %SystemRoot%\System32\systeminfo.exe | %SystemRoot%\System32\findstr.exe /L /C:"Host Name" /C:"OS Name" /C:"OS Version" /C:"Original Install Date" /C:"System Manufacturer" /C:"System Model" /C:"System Type" /C:"Total Physical Memory"
    for /F "tokens=1* delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe BIOS GET SerialNumber /VALUE') do if not "%%J" == "" echo Serial Number:             %%J
    for /F "tokens=1* delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe CPU GET Name /VALUE') do if not "%%J" == "" echo CPU Name:                  %%J
    echo Domain\User Name:          %USERDOMAIN%\%USERNAME%
) >"%ComputerName%.txt"
endlocal

WMIC确定并用ECHO输出的附加数据以与[=的输出相同的格式写入文本文件20=].

注意:最后一个echo命令行在环境变量USERDOMAIN或环境变量USERNAME的值的情况下不安全包含 )&。 100% 安全将是:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
(
    %SystemRoot%\System32\systeminfo.exe | %SystemRoot%\System32\findstr.exe /L /C:"Host Name" /C:"OS Name" /C:"OS Version" /C:"Original Install Date" /C:"System Manufacturer" /C:"System Model" /C:"System Type" /C:"Total Physical Memory"
    for /F "tokens=1* delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe BIOS GET SerialNumber /VALUE') do if not "%%J" == "" echo Serial Number:             %%J
    for /F "tokens=1* delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe CPU GET Name /VALUE') do if not "%%J" == "" echo CPU Name:                  %%J
) >"%ComputerName%.txt"
setlocal EnableDelayedExpansion
echo Domain\User Name:          !USERDOMAIN!\!USERNAME!>>"%ComputerName%.txt"
endlocal
endlocal

为了了解使用的命令及其工作原理,请打开 command prompt window,在其中执行以下命令,并仔细阅读为每个命令显示的所有帮助页面。

  • echo /?
  • endlocal /?
  • findstr /?
  • for /?
  • if /?
  • setlocal /?
  • systeminfo /?
  • wmic /?
  • wmic bios /?
  • wmic bios get /?
  • wmic cpu /?
  • wmic cpu get /?

你能试试这个吗: 使用以下代码创建一个 sysi.vbs 文件,并以这种方式 运行 : cscript //nologo sysi.vbs

根据需要进行调整。

sysi.vbs: '--------------------------------------------

Set dtmConvertedDate = CreateObject("WbemScripting.SWbemDateTime")

    strComputer = "."
    Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\" & strComputer & "\root\cimv2")

    Set colOperatingSystems = objWMIService.ExecQuery ("Select * from Win32_OperatingSystem")

    ' Create a new WshNetwork object to access network properties.
    Wscript.Echo "*** from WScript.Network ***************"

    Set WshNetwork = WScript.CreateObject("WScript.Network")
    Wscript.Echo "Computer name : " & WshNetwork.ComputerName 
    Wscript.Echo "Domain : " & WshNetwork.UserDomain 
    Wscript.Echo "User name : " & WshNetwork.UserName 

    Wscript.Echo "*** from Win32_OperatingSystem  **************"
    For Each objOperatingSystem in colOperatingSystems
        Wscript.Echo "OS Caption: " & objOperatingSystem.Caption
        Wscript.Echo "OS Version: " & objOperatingSystem.Version

        dtmConvertedDate.Value = objOperatingSystem.InstallDate
        dtmInstallDate = dtmConvertedDate.GetVarDate

        Wscript.Echo "OS Install Date: " & dtmInstallDate
        Wscript.Echo "OS Serial Number: " & objOperatingSystem.SerialNumber

    Next

    Set colItems = objWMIService.ExecQuery("Select * from Win32_ComputerSystem",,48)

    Wscript.Echo "*** from Win32_ComputerSystem **********"

    For Each objItem in colItems
        Wscript.Echo "Manufacturer: " & objItem.Manufacturer
        Wscript.Echo "Model: " & objItem.Model
        Wscript.Echo "SystemType: " & objItem.SystemType
        Wscript.Echo "TotalPhysicalMemory: " & objItem.TotalPhysicalMemory
    Next

    Wscript.Echo "*** from Win32_Processor **********"
    Set colItems = objWMIService.ExecQuery("Select * from Win32_Processor",,48)
    For Each objItem in colItems
        Wscript.Echo "Proc Name: " & objItem.Name
        Wscript.Echo "CurrentClockSpeed: " & objItem.CurrentClockSpeed
        Wscript.Echo "ErrorDescription: " & objItem.ErrorDescription
        Wscript.Echo "DeviceID: " & objItem.DeviceID
        Wscript.Echo "Manufacturer: " & objItem.Manufacturer
        Wscript.Echo "MaxClockSpeed: " & objItem.MaxClockSpeed

    Next



    Wscript.Echo "*** from Win32_BIOS ******* "
    Set colBIOS = objWMIService.ExecQuery("Select * from Win32_BIOS")

    Set dtmRelDateRaw = CreateObject("WbemScripting.SWbemDateTime")

    For each objBIOS in colBIOS
         Wscript.Echo "BIOS Name: " & objBIOS.Name
         Wscript.Echo "BIOS Manufacturer: " & objBIOS.Manufacturer
         Wscript.Echo "Primary BIOS: " & objBIOS.PrimaryBIOS

         dtmRelDateRaw.Value = objBIOS.ReleaseDate
         dtmRelDate = dtmRelDateRaw.GetVarDate
         Wscript.Echo "Release Date: " & objBIOS.ReleaseDate
         Wscript.Echo "Release Date: " & dtmRelDate
         Wscript.Echo "Serial Number: " & objBIOS.SerialNumber
         Wscript.Echo "Status: " & objBIOS.Status
         Wscript.Echo "Version: " & objBIOS.Version


    Next