我有一个需要处理和提取数据的日志文件。 每行包含一个事件日志输出的string。 不幸的是,string的部分不是统一的格式。 以下是一些示例行:
"Some random length string. 0x8dda46 0x1 0x384 C:\Program Files (x86)\some\path\foo0.exe " "Some random leeeength string. 0xa95ac2 0x8cc C:\Program Files (x86)\some\path\foo1.exe %%1936 0xcc0 " "Some random leength string. 0xbcd668 0x330 C:\Program Files (x86)\some\path\foo2.exe %%1936 0xf38 " "Some random leeeeeeeength string. 0xbcd668 0x1 0x330 C:\Program Files (x86)\some\path\foo2.exe " "Some random leeength string. 0x352c44 0xfc0 C:\Program Files (x86)\some\path\foo3.exe %%1936 0x92c " "Some random leeeeength string. 0xa95ac2 0x0 0x8cc C:\Program Files (x86)\some\path\foo1.exe " "Some random leength string. 0x352c44 0x0 0xfc0 C:\Program Files (x86)\some\path\foo3.exe "
我需要提取“foo.exe”文件名,而不需要在“C:\ Progra …”(它是进程ID)之前的完整path和HEX值。
所以我想要的输出是:
0x384 foo0.exe 0x8cc foo1.exe 0x330 foo2.exe 0x330 foo2.exe 0xfc0 foo3.exe 0x8cc foo1.exe 0xfc0 foo3.exe
我试图用尽可能less的“硬编码”search/replace来实现目标,因为string的许多部分不会是相同的内容或相同的长度。 我试图用FOR / F来分割string,但是我无法find两列,因为它们总是在变化。 唯一不变的是“C:\ Program Files(x86)”部分。 (Plus FOR有52个variables限制)
我写了一些棘手的batch file,但我开始认为我要求太多的DOS 😉
提前感谢任何帮助!
这实际上是一个调用正则表达式的任务,而对于Windows命令行中的正则表达式,则需要powershell。 幸运的是,您可以从批处理文件或DOS命令提示符运行powershell:
powershell -Command "(Get-Content 'c:\full_path_here\input.log') -replace '.+?(0x[0-9a-f]{3}) .+?\\([^\\]+\.exe).*', '$1 $2'"
这有几个部分
powershell -Command
在引号中运行整个表达式,就像从powershell命令行运行一样 Get-Content
就像linux cat
命令 – 它读取整个文件内容 -replace
使用正则表达式将文件每一行上的内容替换为括号中的两个匹配表达式 @ECHO OFF SETLOCAL FOR /f "tokens=1*delims=." %%a IN (q28333414.txt) DO ( FOR /f "tokens=1*delims=:" %%c IN ("%%~b") DO CALL :process %%c&CALL :report "%%d ) GOTO :EOF :process SET hexval=%~3 IF DEFINED hexval shift&GOTO process SET "hexval=%~1" SET "drive=%~2:" GOTO :eof :report SET "line=%drive%%~1" SET "line="%line:.exe=.exe"%" FOR %%r IN (%line%) DO ECHO %hexval% %%~nxr&GOTO :eof
我使用了一个名为q28333414.txt
的文件, q28333414.txt
包含我的测试数据。
第一个过程简单地抛弃了之间的每个(空格分隔)参数.
和:
直到剩下两个 – 所需的hexval
和驱动器号。
report
进程重新附加驱动器号并将其和.exe
名称括在引号中。 for %%r
选择第一个字符串,删除引号,把结果吐出来,全部完成。
编辑:修复报告只显示文件的名称和扩展名和dbenham评论
最新消息:(字面上!)
@ECHO OFF SETLOCAL enabledelayedexpansion FOR /f "delims=" %%a IN (q28333414.txt) DO SET "line=%%~a"&CALL :process "!line::=" "!" ) GOTO :EOF :process SET "hexval=%~3" IF DEFINED hexval shift&GOTO process CALL :lastbar1 %%~1 SET "filename=%~2" SET filename="c:%filename:.exe =.exe" % FOR %%r IN (%filename%) DO ECHO %hexval% %%~nxr&GOTO :eof GOTO :eof :lastbar1 SET "hexval=%~3" IF DEFINED hexval shift&GOTO lastbar1 SET "hexval=%~1" GOTO :eof
好的 – 那就试试吧。
对于每一行,将所有邪恶冒号替换为" "
,并将结果的引用字符串序列传递给子例程。
移动参数,直到有2个,这将是最后倒数前后的字符串 – 呃冒号。
重复第一个参数的过程。 倒数第二个值是所需的hexval。
用第二个参数,在任何.exe
后加"c:
before和"
,结果是一个带引号的完整文件名和糟粕; 吐出hexval
和文件名并完成…
在“ &
”注释相当昏暗的情况下进行小修改 – 着名的set "var=whatever"
公式在这种情况下失败(包括在子目录“Documents&Settings”中),所以封闭的引号可以作为尾部空格是不相关的。 知道触发问题的测试数据是多么有用 – 减少猜测。
任何一个好的正则表达式工具都可以解决你的问题。 我喜欢使用我的JREPL.BAT混合JScript /批处理实用程序 。 这是纯粹的脚本,从XP以后的任何Windows机器上本机运行。
假设你的文件是test.log,那么我会使用:
jrepl ".* (0x[0-9A-F]+) C:\\Program Files \(x86\)\\(?:.*\\)?([^\\]+\.exe) .*" "$1 $2" /i /f test.log
在每一行上,它会查找以“C:\ Program Files(x86)\”开始并以“.exe”结尾的文件路径前面的空格夹住的最后一个十六进制字符串。 我做了搜索忽略的情况。
此解决方案假定没有反斜杠到随机字符串中。
@echo off setlocal EnableDelayedExpansion for /F "tokens=1-5 delims=\" %%a in (logFile.txt) do ( rem Extract the HEX value for %%A in (%%~a) do ( set "value=!lastButOne!" set "lastButOne=%%A" ) rem Extract the file name for /F %%A in ("%%e") do set "name=%%A" echo !value! !name! )
这是一个混合批处理+ JScript脚本(但仍是一个.bat文件),它将执行类似于NextInLine的PowerShell解决方案的正则表达式替换。
@if (@CodeSection == @Batch) @then @echo off setlocal set "logfile=test.log" rem // Ask JScript to parse log. On each line, %%I = hex. %%J = exe. for /f "tokens=1*" %%I in ('cscript /nologo /e:JScript "%~f0" "%logfile%"') do ( echo %%I %%J ) rem // End main runtime. goto :EOF @end // JScript chimera portion var fso = WSH.CreateObject('Scripting.FileSystemObject'), log = fso.OpenTextFile(WSH.Arguments(0), 1); while (!log.AtEndOfStream) { var line = log.ReadLine(); WSH.Echo(line.replace(/^.+(0x[0-9a-f]+) \w:\\.+?\\(\w+\.exe).+$/i, "$1 $2")); } log.Close();
当然,如果我在你的船,我可能会使用GnuWin32 sed
。
sed -r -e "s/^.*(0x[a-f0-9]+) \w:.+\\(.+\.exe).*$/\1 \2/i" test.log
只是为了笑笑,我对OP的测试日志文件进行了一些时间测试,每次运行完整的解决方案,每次运行几次,得到模式持续时间(结果最常发生)。
sed
:0.015s(最简单) jrepl.bat
:0.051s(强大的瑞士军刀解决方案)