[英]Retain carriage returns in text filtered through a regular expression
我需要搜索日志文件夹,并检索最新日志。 然后,我需要过滤每个日志,提取相关信息并保存到另一个文件。
问题是我用来过滤日志的正则表达式删除了回车符和换行符,因此新文件只包含一堆文本。
$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
Out-File | Select-String -Pattern $reg
,但是我在多行记录上使用Select-String
从未成功。
想看看我是否可以使该正则表达式更好,但是现在,如果您正在使用那些正则表达式模式,则应该将文本文件作为单个字符串读取,这会很有帮助。
$a=get-content $_ -Raw
或者如果您没有PowerShell 3.0
$a=(get-content $_) -join "`r`n"
正如@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'
顺便说一句,不要在循环内使用重定向运算符( >
)。 它将在每次迭代时覆盖输出文件的内容。 如果必须在循环内写入文件,请使用附加重定向运算符( >>
)。 但是,从性能角度考虑,通常最好在流水线的末尾写入输出文件(请参见上文)。
我必须解决在完全不同的环境中换行符消失的问题。 当获取文本文件的内容时,您得到的是一组记录数组,其中每条记录都是一行文本。
我发现在进行一些转换后重新插入换行符的唯一方法是使用自动变量$ OFS(输出字段分隔符)。 默认值为空格,但是如果将其设置为回车换行符,则会在单独的行上获得单独的记录。
因此,请尝试以下操作(可能可行):
$OFS = "`r`n"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.