使用没有文件路径的 findstr 抓取行的批处理脚本
Batch script to grab lines with findstr without filepath
我有一个监控大型系统的日志文件,包括请求和确认。我的 objective 是能够:
1. 遍历脚本并获取请求及其确认发生的行
2. 将重要的整行拉为字符串并将它们存储为变量以供字符串修改以输出到其他地方。
这是我目前的情况:
@ECHO off
setlocal
setlocal enabledelayedexpansion
setlocal enableextensions
:: Lets get today's date, formatted the way the ABCD File is named
for /f "tokens=1-5 delims=/ " %%d in ("%date%") do set targetDate=%%f-%%d-%%e
:: Now we set the targetFile name
SET ABCDLogsFile=C:\Users\me\Documents\monitoring_file_for_jim\ABCDFIX*%targetDate%.log
::****Scrapped original approach*****
set "ackFoundCount=0"
set "reqFoundCount=0"
::Get lines with acks
for /f delims^=^ eol^= %%a in ('findstr /c:"\<ACK\>" "%ABCDLogsFile%"') do (
set /a "ackFoundCount+=1"
setlocal enabledelayedexpansion
for %%N in (!ackFoundCount!) do (
endlocal
set "ackFound%%N=%%a"
)
)
::Get lines with requests
for /f delims^=^ eol^= %%b in ('findstr /c:"ReqSingle" "%ABCDLogsFile%"') do (
set /a "reqFoundCount+=1"
setlocal enabledelayedexpansion
for %%N in (!reqFoundCount!) do (
endlocal
set "reqFound%%N=%%b"
)
)
setlocal enabledelayedexpansion
for /l %%N in (1,1,2 %reqFoundCount%) do echo REQ %%N FOUND= !reqFound%%N!
pause
for /l %%N in (1,1,2 %ackFoundCount%) do echo ACK %%N FOUND= !ackfound%%N!
endlocal
编辑 2 dbenham
我之前尝试完成此任务的迂回方式完全没有必要。
感谢这里的问答:
'findstr' with multiple search results (BATCH)
我的脚本工作方式类似。但是,我很好奇是否有可能在开头没有文件路径的情况下获得 findstr 输出。我只需要在日志中提取时间戳,它总是每行的前 12 个字符(没有文件路径)。我的输出当前以路径为前缀,虽然我可以获得日志最终用于生产的路径,但尝试以其他方式进行操作会更安全。在这个脚本最终成为 运行 时,每个请求和确认只有 1 或 2 个,这就是我存储所有找到的原因。没有必要,但我认为如果有两个,看到两个会让人放心。以下是类似 acks 和 reqs 的输出:
C:\Users\me\Documents\monitoring_file_for_jim\ABCDFIX 2015-04-01.log:2015-03-26 07:00:11,028 INFO etc...
我在想,如果我可以从一开始就去掉文件路径,那么我需要做的就是 事件的时间戳
for /l %%N in (1,1,1 %reqFoundCount%) do echo Req %%N occurred at: !reqFound%%N:~0,12! >> MorningAckChecks.txt
for /l %%N in (1,1,1 %ackFoundCount%) do echo ACK %%N occurred at: !ackfound%%N:~0,12! >> MorningAckChecks.txt
这个post变得有点乱了。如果您 post 编辑了与您得到的输出相对应的输入行,那将非常有帮助。如果您不能这样做,请在您的 FOR 之前添加此语句。我相信你会发现 testReqSkip 是空白的。
echo.testReqSkip=%testReqSkip%
我怀疑您无法让 SKIP 工作,因为您正在使用 FOR 语句迭代分隔的行号列表,这意味着该数字在 FOR 变量中。问题是,在指定 SKIP 值或任何其他 FOR 选项时,您不能包含 FOR 变量或(延迟扩展)。批处理解析器在扩展 FOR 变量之前评估 FOR 选项,因此它不可能工作。当包含变量作为 FOR 选项的一部分时,只能使用正常扩展。
但我完全不明白您为什么认为需要行号。 FINDSTR 已经能够解析出你想要的行。只需使用 FOR /F 来迭代每个匹配的行。对于每一行,定义一个包含行内容的变量,然后使用子字符串操作解析出您想要的值。
但我可以提供一个替代方案,我认为它可以让您的生活更轻松。 JREPL.BAT 是一个复杂的正则表达式文本处理器,可以一次性识别行并解析和转换您想要的值。 JREPL.BAT 是一个混合 JScript/batch 脚本,可以在任何 Windows XP 以后的机器上本地运行。
如果我知道你的输入是什么样子的,以及你想要的输出是什么,那么我可能会使用 JREPL.BAT 敲出一个简单的解决方案。或者您可以阅读大量的内置文档并自己找出答案。
通过 jrepl /?
从命令行访问文档。您可能希望通过 MORE 传输输出,以便一次获得一个屏幕的帮助。但我从来没有这样做,因为我的命令行控制台配置了一个大的输出缓冲区,所以我可以简单地向上滚动以查看过去的输出。
编辑 - 回应评论和更新的问题
以下是导致问题的相关代码片段。
SET ABCDLogsFile=C:\Users\me\Documents\monitoring_file_for_jim\ABCDFIX*%targetDate%.log
findstr /c:"\<ACK\>" "%ABCDLogsFile%"
findstr /c:"ReqSingle" "%ABCDLogsFile%
问题是您的 ABCDLogsFile 定义包含一个通配符,这会导致 FINDSTR 在每个匹配行前加上匹配发生的文件名的完整路径。
我有一个简单的解决方案 - 只需按如下方式更改 ABCDLogsFile 的定义:
SET "ABCDLogsFile=C:\Users\me\Documents\monitoring_file_for_jim\ABCDFIX<%targetDate%.log"
说明
我的解决方案依赖于两个未记录的功能
1) 未记录的文件掩码通配符。
<
- 与 *
非常相似
>
- 与 ?
非常相似
这些符号通常用于重定向,因此如果您想将它们用作文件掩码通配符,则必须将它们加引号或转义。
我们在 DosTips 上讨论了未记录的功能 - Dir undocumented wildcards。散布在整个线程(和 link)中的是一些示例用例。
我在 http://www.dostips.com/forum/viewtopic.php?p=39420#p39420
记录了我对非标准通配符具体工作原理的理解
2) FINDSTR 使用非标准通配符
如果出现以下任一情况,FINDSTR 将在每个匹配行前加上文件名(可能还有路径)
- 使用了
/M
选项
- 使用了
/F
选项
- 命令行中明确列出了多个输入文件
- 通过文件掩码隐含多个输入文件,在命令行上至少有一个
*
或 ?
通配符
您正在获取文件路径前缀,因为最后一个触发器 - 文件掩码中的 *
。
但是您可以使用 <
来获得相同的结果,除了非标准通配符不会触发输出中的文件前缀。
问题已解决:-)
我在 http://www.dostips.com/forum/viewtopic.php?p=39464#p39464 讨论了这个 FINDSTR 功能。
有一天我希望用这个美味的小花絮来更新我的 What are the undocumented features and limitations of the Windows FINDSTR command? post。
我有一个监控大型系统的日志文件,包括请求和确认。我的 objective 是能够:
1. 遍历脚本并获取请求及其确认发生的行
2. 将重要的整行拉为字符串并将它们存储为变量以供字符串修改以输出到其他地方。
这是我目前的情况:
@ECHO off
setlocal
setlocal enabledelayedexpansion
setlocal enableextensions
:: Lets get today's date, formatted the way the ABCD File is named
for /f "tokens=1-5 delims=/ " %%d in ("%date%") do set targetDate=%%f-%%d-%%e
:: Now we set the targetFile name
SET ABCDLogsFile=C:\Users\me\Documents\monitoring_file_for_jim\ABCDFIX*%targetDate%.log
::****Scrapped original approach*****
set "ackFoundCount=0"
set "reqFoundCount=0"
::Get lines with acks
for /f delims^=^ eol^= %%a in ('findstr /c:"\<ACK\>" "%ABCDLogsFile%"') do (
set /a "ackFoundCount+=1"
setlocal enabledelayedexpansion
for %%N in (!ackFoundCount!) do (
endlocal
set "ackFound%%N=%%a"
)
)
::Get lines with requests
for /f delims^=^ eol^= %%b in ('findstr /c:"ReqSingle" "%ABCDLogsFile%"') do (
set /a "reqFoundCount+=1"
setlocal enabledelayedexpansion
for %%N in (!reqFoundCount!) do (
endlocal
set "reqFound%%N=%%b"
)
)
setlocal enabledelayedexpansion
for /l %%N in (1,1,2 %reqFoundCount%) do echo REQ %%N FOUND= !reqFound%%N!
pause
for /l %%N in (1,1,2 %ackFoundCount%) do echo ACK %%N FOUND= !ackfound%%N!
endlocal
编辑 2 dbenham
我之前尝试完成此任务的迂回方式完全没有必要。 感谢这里的问答:
'findstr' with multiple search results (BATCH)
我的脚本工作方式类似。但是,我很好奇是否有可能在开头没有文件路径的情况下获得 findstr 输出。我只需要在日志中提取时间戳,它总是每行的前 12 个字符(没有文件路径)。我的输出当前以路径为前缀,虽然我可以获得日志最终用于生产的路径,但尝试以其他方式进行操作会更安全。在这个脚本最终成为 运行 时,每个请求和确认只有 1 或 2 个,这就是我存储所有找到的原因。没有必要,但我认为如果有两个,看到两个会让人放心。以下是类似 acks 和 reqs 的输出:
C:\Users\me\Documents\monitoring_file_for_jim\ABCDFIX 2015-04-01.log:2015-03-26 07:00:11,028 INFO etc...
我在想,如果我可以从一开始就去掉文件路径,那么我需要做的就是 事件的时间戳
for /l %%N in (1,1,1 %reqFoundCount%) do echo Req %%N occurred at: !reqFound%%N:~0,12! >> MorningAckChecks.txt
for /l %%N in (1,1,1 %ackFoundCount%) do echo ACK %%N occurred at: !ackfound%%N:~0,12! >> MorningAckChecks.txt
这个post变得有点乱了。如果您 post 编辑了与您得到的输出相对应的输入行,那将非常有帮助。如果您不能这样做,请在您的 FOR 之前添加此语句。我相信你会发现 testReqSkip 是空白的。
echo.testReqSkip=%testReqSkip%
我怀疑您无法让 SKIP 工作,因为您正在使用 FOR 语句迭代分隔的行号列表,这意味着该数字在 FOR 变量中。问题是,在指定 SKIP 值或任何其他 FOR 选项时,您不能包含 FOR 变量或(延迟扩展)。批处理解析器在扩展 FOR 变量之前评估 FOR 选项,因此它不可能工作。当包含变量作为 FOR 选项的一部分时,只能使用正常扩展。
但我完全不明白您为什么认为需要行号。 FINDSTR 已经能够解析出你想要的行。只需使用 FOR /F 来迭代每个匹配的行。对于每一行,定义一个包含行内容的变量,然后使用子字符串操作解析出您想要的值。
但我可以提供一个替代方案,我认为它可以让您的生活更轻松。 JREPL.BAT 是一个复杂的正则表达式文本处理器,可以一次性识别行并解析和转换您想要的值。 JREPL.BAT 是一个混合 JScript/batch 脚本,可以在任何 Windows XP 以后的机器上本地运行。
如果我知道你的输入是什么样子的,以及你想要的输出是什么,那么我可能会使用 JREPL.BAT 敲出一个简单的解决方案。或者您可以阅读大量的内置文档并自己找出答案。
通过 jrepl /?
从命令行访问文档。您可能希望通过 MORE 传输输出,以便一次获得一个屏幕的帮助。但我从来没有这样做,因为我的命令行控制台配置了一个大的输出缓冲区,所以我可以简单地向上滚动以查看过去的输出。
编辑 - 回应评论和更新的问题
以下是导致问题的相关代码片段。
SET ABCDLogsFile=C:\Users\me\Documents\monitoring_file_for_jim\ABCDFIX*%targetDate%.log
findstr /c:"\<ACK\>" "%ABCDLogsFile%"
findstr /c:"ReqSingle" "%ABCDLogsFile%
问题是您的 ABCDLogsFile 定义包含一个通配符,这会导致 FINDSTR 在每个匹配行前加上匹配发生的文件名的完整路径。
我有一个简单的解决方案 - 只需按如下方式更改 ABCDLogsFile 的定义:
SET "ABCDLogsFile=C:\Users\me\Documents\monitoring_file_for_jim\ABCDFIX<%targetDate%.log"
说明
我的解决方案依赖于两个未记录的功能
1) 未记录的文件掩码通配符。
<
- 与*
非常相似
>
- 与?
非常相似
这些符号通常用于重定向,因此如果您想将它们用作文件掩码通配符,则必须将它们加引号或转义。
我们在 DosTips 上讨论了未记录的功能 - Dir undocumented wildcards。散布在整个线程(和 link)中的是一些示例用例。
我在 http://www.dostips.com/forum/viewtopic.php?p=39420#p39420
记录了我对非标准通配符具体工作原理的理解2) FINDSTR 使用非标准通配符
如果出现以下任一情况,FINDSTR 将在每个匹配行前加上文件名(可能还有路径)
- 使用了
/M
选项 - 使用了
/F
选项 - 命令行中明确列出了多个输入文件
- 通过文件掩码隐含多个输入文件,在命令行上至少有一个
*
或?
通配符
您正在获取文件路径前缀,因为最后一个触发器 - 文件掩码中的 *
。
但是您可以使用 <
来获得相同的结果,除了非标准通配符不会触发输出中的文件前缀。
问题已解决:-)
我在 http://www.dostips.com/forum/viewtopic.php?p=39464#p39464 讨论了这个 FINDSTR 功能。
有一天我希望用这个美味的小花絮来更新我的 What are the undocumented features and limitations of the Windows FINDSTR command? post。