批处理文件 - 搜索单词并提取变量中的下一个单词

时间:2017-11-03 13:17:55

标签: batch-file search file-search

我有一个日志文件,其中包含大量没有特定格式的文本。它有一个特殊的变量' SId'随着文件的进展,已经分配了很多值。 例如:

For the first line le=24 we have SId = 23 and then,
on second it's SId = 56, following the be = 45 which......

我正在尝试创建一个批处理文件,该文件将读取整个文件并找到变量' SId'的最后指定值。有可能吗?

3 个答案:

答案 0 :(得分:1)

首先,问题的答案是:是的,这是可能的。

但是我认为,对于每个阅读问题的人来说,还有一点感兴趣,如何来获取最后一个SId号码。嗯,使用有限的Windows命令解释器功能从具有未知数据格式的文本文件中获取此数字非常困难。出于这个原因,这个纯粹和糟糕的任务描述对我来说很有趣,我接受了这个编码挑战。

我在C:\Temp创建了一个文件Test File.log,其中包含以下三行:

For the first line we have SId = 23 and then,
the second line contains nothing interesting despite SId=x8434
;on third it's "! SId  = 56, following SId=8434which ... SId34234 ... !" SId 

最后一行以分号开头,这是用 FOR 解析的行上的问题,因为eol=;是默认值,导致默认忽略这些行。

最后一行还包含双引号,这需要在处理此行时延迟环境变量扩展,以及两个感叹号,它们很容易导致替换两个!以及在处理此行时延迟之间的所有内容扩展正在启用。

最后一行还包含4次SId。前两个SId在等号周围有不同数量的空格,第三个SId没有等号,因此要忽略,并且在最后SId之后只有一个空格。

下面的批处理代码针对感兴趣的读者进行了评论,但用于确定上次有效SId次出现的数字的代码块除外。对于批量编程的初学者来说,这部分代码很难解释。通过从批处理文件顶部删除@echo off,从命令提示符窗口中运行批处理文件并查看输出命令行,可以更容易理解此代码部分的工作原理。

带有 FOR 循环的ProcessLine块和子例程GetNumber使用示例Test File.log执行四次,值为:

  = 56, following SId=8434which ... SId34234 ... !" SId 
=8434which ... SId34234 ... !" SId 
34234 ... !" SId 
 

注意:每个Value都以尾随空格结尾。

这个一般性描述的任务的批处理代码:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "LogFile=C:\Temp\Test File.log"
if not exist "%LogFile%" goto EndBatch

rem Use command FINDSTR to search for all lines containing case-sensitive
rem the string "SId = " without or with spaces around the equal sign and
rem at least one digit. Output by FINDSTR are the lines matching this regular
rem expression with line number and a colon at beginning because of option /N.
rem The option /N is used to make sure that no line with SId starts with a
rem semicolon as those lines would be ignored by default by FOR. The last
rem line with a string matching this simple regular expression is assigned
rem to variable LastLine. Otherwise this environment variable deleted
rem before the loop still does not exist after the loop finished.

set "LastLine="
for /F "delims=" %%I in ('%SystemRoot%\System32\findstr.exe /N /R /C:"SId *= *[0123456789]" "%LogFile%"') do set "LastLine=%%I"
if not defined LastLine goto EndBatch

rem The last line contains perhaps multiple times an equal sign and perhaps
rem even multiple "SId" (secure identifier) strings. So it is necessary to
rem process this last line really the hard way. And it is better to process
rem the line perhaps containing also double quotes or other characters with
rem a special meaning for the Windows command interpreter using delayed
rem environment variable expansion.

setlocal EnableDelayedExpansion
set "Identifier="

:ProcessLine
set "Value=!LastLine:*SID=!"
if not defined Value goto LineProcessed
if "!Value!" == "!LastLine!" goto LineProcessed

for /F "tokens=1,2" %%A in ("!Value!") do (
    set "LastID="
    if "%%A" == "=" (
        set "Number=%%B"
        call :GetNumber
    ) else (
        set "Number=%%A"
        if "!Number:~0,1!" == "=" (
            set "Number=!Number:~1!"
            call :GetNumber
        )
    )
    if defined LastID set "Identifier=!LastID!"
    set "LastLine=!Value!"
    goto ProcessLine
)
set "LastLine=!Value!"
goto ProcessLine

:GetNumber
if not defined Number goto :EOF
set "IsDigit=1"
for /F "delims=0123456789" %%I in ("!Number:~0,1!") do set "IsDigit=0"
if %IsDigit% == 0 goto :EOF
set "LastID=%LastID%%Number:~0,1%"
set "Number=!Number:~1!"
goto GetNumber

rem Pass the last found identifier from current environment with delayed
rem expansion to previous environment on restoring previous environment.

:LineProcessed
endlocal & set "Identifier=%Identifier%"
if not defined Identifier goto EndBatch

echo Last SId found: %Identifier%

rem Other command lines which process the found identifier.

:EndBatch
endlocal

此批处理文件的输出例如Test File.log为:

Last SId found: 8434

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

  • call /?
  • echo /?
  • endlocal /?
  • findstr /?
  • for /?
  • goto /?
  • if /?
  • rem /?
  • set /?
  • setlocal /?

Single line with multiple commands using Windows batch file解释了在一个命令行中使用的&运算符。

答案 1 :(得分:0)

如果没有看到实际的日志文件内容,就很难提供一个强大的示例,但通常如果SId是每行的第一个字符串,则以下两个FindStr示例中的一个可能就足够了: / p>

@For /F "Tokens=1,3" %%A In ('FindStr/BRC:"SId[ ]=[ ][0-9]*" "file.log"') Do @Set "%%A=%%B"
@Echo %SId%
@Pause
@For /F "Tokens=1,3" %%A In ('FindStr/RC:"^SId\ =\ [0-9]*" "file.log"') Do @Set "%%A=%%B"
@Echo %SId%
@Pause

您的最后一个值将分配给名为%SId%的变量。我使用file.log作为日志文件的名称,根据需要进行调整。要查找FindStr的选项/开关,请在命令提示符处输入FindStr/?

答案 2 :(得分:0)

批次并不是为这些事情做的。以下取决于一些事项:
- SId=之间有一个空格,=后面有一个空格(可以使用find字符串更改) - 在值或值是该行的最后一项之后,有一个有效的分隔符(空格,制表符,逗号,=)。

@echo off 
SETLOCAL EnableDelayedExpansion
for /f "delims=" %%a in ('type t.txt^|find "SId = "') do (
  set "line=%%a"
  set "line=!line:*SId =!
  set /a "last=!line:~1!" 2>nul
)
echo %last%

诀窍是删除从开始到(包括)搜索字符串的任何内容(遗憾的是=无法用此删除)然后使用其余的(减去第一个字符,即使用= set /a}将数字分配给变量  有一个错误消息"缺少操作数"如果是数字后面的字符串部分,则重定向到NUL。