我需要搜索日志文件夹并检索最新日志。然后我需要过滤每个日志,提取相关信息并保存到另一个文件。
问题是我用来过滤日志的正则表达式正在删除回车符和换行符,所以新文件只包含一堆混乱的文本。
$Reg = "(?ms)\*{6}\sBEGIN(.|\n){98}13.06.2015(.|\n){104}00000003.*(?!\*\*)+"
get-childitem "logfolder" -filter *.log |
where-object {$_.LastAccessTime -gt [datetime]$Test.StartTime} |
foreach {
$a=get-content $_;
[regex]::matches($a,$reg) | foreach {$_.groups[0].value > "MyOutFile"}
}
日志结构:
******* BEGIN MESSAGE *******
<Info line 1>
Date 18.03.2010 15:07:37 18.03.2010
<Info line 2>
File Number: 00000003
<Info line 3>
*Variable number of lines*
******* END MESSAGE *******
基本上捕获BEGIN
和END
之间的所有内容,其中日期和文件编号是特定值。有没有人知道如何在不丢失换行符的情况下做到这一点?我也尝试使用Out-File | Select-String -Pattern $reg
,但我在多行记录中使用Select-String
时从未取得过成功。
答案 0 :(得分:2)
想知道我是否可以更好地制作正则表达式,但是现在如果你使用这些正则表达式模式,你应该把你的文本文件作为单个字符串阅读,这有很大帮助。
text
或者如果您没有PowerShell 3.0
>>> import re
>>> p = re.search('[0-9]{1,3}\.[0-9]{2}', price)
>>> price = p.group(0)
>>> print price
答案 1 :(得分:2)
正如@Matt指出的那样,如果要进行多行匹配,则需要将整个文件作为单个字符串读取。否则,您的(多行)正则表达式将一个接一个地应用于单行。有几种方法可以将文件的内容作为单个字符串获取:
(Get-Content 'C:\path\to\file.txt') -join "`r`n"
Get-Content 'C:\path\to\file.txt' | Out-String
Get-Content 'C:\path\to\file.txt' -Raw
(需要PowerShell v3或更新版本)[IO.File]::ReadAllText('C:\path\to\file.txt')
另外,我稍微修改了正则表达式。大多数时间日志消息的长度可能不同,因此如果日志消息发生更改,则匹配的固定长度可能会失败。最好匹配字符串的不变部分,并将其余部分保留为可变长度匹配。而且我个人发现在几个步骤中进行这种内容提取要容易得多(使得更简单的正则表达式)。在您的情况下,我首先将日志条目彼此分开,然后过滤内容:
$date = [regex]::Escape('13.06.2015')
$fnum = '00000003'
$re1 = "(?ms)\*{7} BEGIN MESSAGE \*{7}\s*([\s\S]*?)\*{7} END MESSAGE \*{7}"
$re2 = "(?ms)[\s\S]*?Date\s+$date[\s\S]*?File Number:\s+$fnum[\s\S]*"
Get-ChildItem 'C:\log\folder' -Filter '*.log' | ? {
$_.LastAccessTime -gt [DateTime]$Test.StartTime
} | % {
Get-Content $_.FullName -Raw |
Select-String -Pattern $re1 -AllMatches |
select -Expand Matches |
% {
$_.Groups[1].Value |
Select-String -Pattern $re2 |
select -Expand Matches |
select -Expand Groups |
select -Expand Value
}
} | Set-Content 'C:\path\to\output.txt'
顺便说一下,不要在循环中使用重定向运算符(>
)。它会在每次迭代时覆盖输出文件的内容。如果必须写入循环内的文件,请使用append重定向运算符(>>
)。但是,在性能方面,通常最好将写入输出文件放在管道的末尾(见上文)。
答案 2 :(得分:1)
我必须解决在完全不同的背景下消失换行的问题。当您执行文本文件的get-content时获得的是一组记录,其中每条记录都是一行文本。
我发现在转换后将换行符放回原位的唯一方法是使用自动变量$ OFS(输出字段分隔符)。默认值为space,但如果将其设置为回车换行符,则会在单独的行上获得单独的记录。
所以试试这个(可能会有效):
$OFS = "`r`n"