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

问题描述 投票:0回答:3

我正在处理批处理文件并导出到文本文件。看起来一切都很好,但是当我打开文本文件时,许多新行中断。所以,我想删除它们。

@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
batch-file text-files line-breaks wmic system-information
3个回答
3
投票

%SystemRoot%\System32\systeminfo.exe
的操作系统语言相关输出是采用 ASCII/ANSI/OEM 的字符编码,这意味着使用在命令提示符窗口中运行时显示的代码页每个字符一个字节
chcp
。代码页取决于为用于运行批处理文件的帐户配置的国家(地区)。只要感兴趣的数据不包含代码值大于 127 的字符(非 ASCII 字符),代码页并不重要。

systeminfo
过滤的
findstr
的输出是二进制文件,冒号左侧为文件中的十六进制偏移量、字节的十六进制值以及分号后的 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
的输出始终使用UTF-16Little Endian编码和字节顺序标记(BOM)进行Unicode编码。因此,两个使用的
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。换行符为回车符 (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 编码的回车 + 换行 (0D 00 0A 00) 都会变成 ASCII 编码的回车 + 回车 + 换行 (0D 0D 0A)。

这才是真正的问题。使用正则表达式搜索字符串

.
来匹配具有至少一个字符的所有行,以及在从 Unicode 转换为 ASCII 的输出中空行与此正则表达式搜索字符串匹配时,额外的回车结果会不正确。

这取决于所使用的文本编辑器如何解释无效的换行符序列。大多数文本编辑器将不带换行的回车解释为行终止,但

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
    被省略,因为实际上并不需要。从 Unicode 到 ASCII 的不正确转换是由 Windows 命令处理器完成的
    cmd.exe
  2. 此批处理文件未启用延迟环境变量扩展,因为根本不需要。
  3. 所有可执行文件均使用众所周知的完全限定文件名指定。因此
    cmd.exe
    不必使用环境变量
    PATHEXT
    PATH
    的值来搜索可执行文件。
  4. WMIC 选项
    /Format:list
    被选项
    /VALUE
    替换,这会产生相同的输出。
  5. 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 输出的附加数据以与

systeminfo
的输出相同的格式写入文本文件。

注意: 最后一个

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

要了解所使用的命令及其工作原理,请打开命令提示符窗口,执行以下命令,并完整、仔细地阅读每个命令显示的帮助页面。

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

1
投票

你可以试试这个吗: 使用以下代码创建 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

1
投票

只是不使用

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
© www.soinside.com 2019 - 2024. All rights reserved.