可能
我有一个格式很奇怪的日志文件,我想将其转换为表。格式是每行包含多个键值对(每行相同)。我想转换这些行,以便每个属性成为包含该行值的表中的一列。
请注意,原始日志文件每行包含39个属性,日志文件约为80MB。
示例行:
date=2019-12-02 srcip=8.8.8.8 destip=8.8.4.4 srcintf="port2"
date=2019-12-01 srcip=8.8.8.8 destip=8.8.4.4 srcintf="xyz abc"
date=2019-12-03 srcip=8.8.8.8 destip=8.8.4.4 srcintf="port2"
date=2019-12-05 srcip=8.8.8.8 destip=8.8.4.4 srcintf="port2"
date=2019-12-07 srcip=8.8.8.8 destip=8.8.4.4 srcintf="port2"
我尝试过:
Get-Content .\testfile.log | select -First 10 | ConvertFrom-String | select p1, p2, p3 | ft | Format-Wide
但是这不会将属性名称分解为列名称。因此,在此示例中,我希望P1是日期,p2 srcip和p3 destip,并且希望删除每个值的第一部分。
任何人都有任何技巧或创意,如何将其转换为表格?
ConvertFrom-String
提供基于分隔符的解析以及基于包含示例值的模板的基于启发式的解析。基于分隔符的解析会应用您无法控制的自动类型转换,并且模板语言的文档很少,其确切行为难以预测-最好完全避免使用此cmdlet。另请注意,它在PowerShell Core中不可用。
相反,我建议基于ConvertFrom-String
和switch
statement的方法来创建代表日志行的自定义对象(switch
)的集合:
-split
operator
注意:
以上假定您的值具有无嵌入空格;如果这样做,则需要做更多工作-请参阅下一部分。
要在variable中捕获生成的自定义对象,只需使用-split
[pscustomobject]
成为# Use $objects = switch ...` to capture the generated objects in a variable.
switch -File .\testfile.log { # Loop over all file lines
default {
$oht = [ordered] @{ } # Define an aux. ordered hashtable
foreach ($keyValue in -split $_) { # Loop over key-value pairs
$key, $value = $keyValue -split '=', 2 # Split pair into key and value
$oht[$key] = $value -replace '^"|"$' # Add to hashtable with "..." removed
}
[pscustomobject] $oht # Convert to custom object and output.
}
}
实例的$objects = switch ...
数组。如果即使在日志行仅是[[one的情况下也要确保$objects
也成为数组,请使用[object[]]
([pscustomobject]
实际上与$objects
相同)。pipeline
[array] $objects = switch ...
语句括在[array]
中>[object[]]
的变量(例如[
switch
]内部的支持具有嵌入式空格的值
& { ... }
):此外,周围的date srcip destip srcintf
---- ----- ------ -------
2019-12-02 8.8.8.8 8.8.4.4 port2
2019-12-01 8.8.8.8 8.8.4.4 port2
2019-12-03 8.8.8.8 8.8.4.4 port2
2019-12-05 8.8.8.8 8.8.4.4 port2
2019-12-07 8.8.8.8 8.8.4.4 port2
被删除。"..."
请注意,不支持嵌入式转义
srcintf="port 2"
实例(例如"..."
将不起作用。说明:switch -file .\testfile.log {
default {
$oht = [ordered] @{ }
foreach ($keyValue in $_ -split '(\w+=(?:[^"][^ ]*|"[^"]*"))' -notmatch '^\s*$') {
$key, $value = $keyValue -split '=', 2
$oht[$key] = $value -replace '^"|"$'
}
[pscustomobject] $oht
}
}
被与"
和srcintf="port \"2\""
标记匹配的$_ -split '(\w+=(?:[^"][^ ]*|"[^"]*"))'
分割,并通过将表达式包含在regex中(创建捕获组),includes
这些“分隔符key=valueWithoutSpaces
输出的令牌中(默认情况下不包含分隔符)。key="value that may have spaces"
然后从结果中清除空的和全空格的标记(“数据标记”,在我们的情况下不重要),实际上仅留下键值对。(...)
将给定的键值令牌再见-split
分成两个令牌,并使用解构分配将键和值分配给单独的变量。]>-notmatch '^\s*$'
将一个条目添加到辅助。带有键和值的哈希表,其中$key, $value = $keyValue -split '=', 2
使用=
从值的开头和结尾(如果存在)中删除$oht[$key] = $value -replace '^"|"$'
。可能
-replace '^"|"$'
。这种方法有两个警告。为简单起见,您的源数据是用空格分隔的。如果您的实际数据包含空格(可以缓解),则会中断。另一个明显的警告是您无法保证属性顺序。 -replace
operator输出:
-replace
确定,出于讨论的目的,我将假设以下内容:数据在PSDATA.TXT文件中
"
...将生成一个表,其中文件中的每一行都变为PSObject,其中字段以每个名称/值对中的名称作为名称,而字段的相关值则作为字符串。如果您不使用PowerShell v4或更高版本(我不确定3),则可以省略ConvertFrom-StringData
,而PSObject中字段顺序的副作用不一定与文件。[如果您想拥有这些PSObject的数组以进行进一步处理,则可以将上面的整行包装在变量分配中,例如
Get-Content c:\temp\so.txt | ForEach-Object{ [PSCustomObject](($_ -split " ") -join "`r`n" | ConvertFrom-StringData) } | Select-Object date, srcip, destip, srcintf
,如果您想将其发送到CSV文件,则只需添加date srcip destip srcintf ---- ----- ------ ------- 2019-12-02 8.8.8.8 8.8.4.4 "port2" 2019-12-01 8.8.8.8 8.8.4.4 "port2" 2019-12-03 8.8.8.8 8.8.4.4 "port2" 2019-12-05 8.8.8.8 8.8.4.4 "port2" 2019-12-07 8.8.8.8 8.8.4.4 "port2"
到结尾。
Get-Content -Path PSDATA.TXT |
ForEach-Object {$_ -replace ' ','";' -replace '=','="' -replace '""','"'} |
ForEach-Object {New-Object PSObject -Property (Invoke-Expression ("[Ordered]@{{{0}}}" -f $_))}
可能