我有一个很大的文件,其中包含很多行。例如:
ts=2019-01-16 network=1.1.1.1 system=irgendwas pid=100 bugReq=dasf something=else maybe=this
我想从每一行中提取以下信息:
ts=,system= & something=
,但=
之后的值始终会更改。
我已经尝试过了,但是无法正常工作:
$found = $string -match '.*system="(\d+)".*' if ($found) { $system= $matches[1]}
答案 0 :(得分:5)
这是另一个解决方案。 [ grin ]它使用ConvertFrom-StringData
cmdlet将输入解析为对象。然后它仅创建一个需要道具的[PSCustomObject]。最后,它将每个对象发送到$ Results集合。
在这种情况下,最终定制对象的构造使以下信息不重要,但重要的是要知道ConvertFrom-StringData
cmdlet的输出是标准哈希表。这意味着对象的顺序几乎可以肯定不是原始顺序。 不要期望事物按照它们在源中出现的顺序。
[edit =添加了一条新的数据行,该行具有嵌入的空格和更新的-replace
模式来处理。]
# fake reading in a text file
# in real life, use Get-Content
$InStuff = @(
'ts=2019-01-16 network=1.1.1.1 system=irgendwas pid=100 bugReq=dasf something=else maybe=this'
'ts=2019-01-16 network=1.1.1.2 system=PC-001 pid=100 bugReq=dasf something=OtherElse maybe=this'
'ts=2019-01-16 network=1.1.1.66 system=PC-666 pid=100 bugReq=dasf something=ThisELse maybe=this'
'ts=2019-01-16 network=1.1.1.3 system=PC-123 pid=100 bugReq=dasf something=AnotherElse maybe=this'
'ts=2019-01-16 network=1.1.1.4 system=PC-004 Oo-LaLa another value with WhiteSpace id=100 bugReq=dasf something=Else-ish with Whitespace'
)
$Results = foreach ($IS_Item in $InStuff)
{
# this requires that spaces ONLY be found as delimiters
# if you have embedded spaces, some sort of data format adjustment will be required
# now there is a need for handline embedded whitespace
#$IS_Item -replace ' ', [environment]::NewLine |
$IS_Item -replace '(\w{1,}=)', ('{0}{1}' -f [environment]::NewLine, '$1') |
ConvertFrom-StringData |
ForEach-Object {
[PSCustomObject]@{
TS = $_.ts
System = $_.system
Something = $_.something
}
}
}
$Results
在屏幕上输出...
TS System Something
-- ------ ---------
2019-01-16 irgendwas else
2019-01-16 PC-001 OtherElse
2019-01-16 PC-666 ThisELse
2019-01-16 PC-123 AnotherElse
2019-01-16 PC-004 Oo-LaLa another value with WhiteSpace Else-ish with Whitespace
这是简单对象的适当集合,因此它将Export-CSV
非常整洁。 [咧嘴]
答案 1 :(得分:1)
假设每行的键值对列表仅包含值,而没有嵌入的空格或引号:
# Sample input line.
$line = 'ts=2019-01-16 network=1.1.1.1 system=irgendwas pid1=100 bugReq=dasf something=else maybe=this'
# Parse the line into key-value pairs and create a variable for each.
$i = 0
foreach ($keyOrValue in $line -split '[= ]') {
if ($i++ % 2 -eq 0) { $varName = $keyOrValue }
else { Set-Variable $varName $keyOrValue }
}
# $ts now contains '2019-01-16', $network '1.1.1.1', $system 'irgendwas', ...
请注意,我是如何稍微修改示例输入行以将pid
更改为pid1
,因为PowerShell不允许您创建$PID
变量,因为它是< em> automatic 变量,反映当前会话的PID(进程ID)。
另一个选择(也可以避免变量名冲突)是为每个输入行创建一个 hashtable :
# Sample input line.
$line = 'ts=2019-01-16 network=1.1.1.1 system=irgendwas pid=100 bugReq=dasf something=else maybe=this'
# Parse the line into key-value pairs and create a variable for each.
$htValues = @{} # Initialize the hashtable.
$i = 0
foreach ($keyOrValue in $line -split '[= ]') {
if ($i++ % 2 -eq 0) { $varName = $keyOrValue }
else { $htValues[$varName] = $keyOrValue }
}
# $htValues now has keys 'ts', 'network', 'system' with corresponding
# values, so you can access $htValues.ts to get '2019-01-16', for instance.
这种方法的另一个优势是可以借用自己收集为整体数组中的各个行创建的哈希表(例如,$hashTableArray = foreach ($line in ...) { ... }
-尽管一个非常大的文件,可能无法选择。
借用Lee_Dailey's answer的想法,您可以选择使用ConvertFrom-StringData
cmdlet创建哈希表,之后首先借助{{1}将每个键值对放在自己的行中}运算符:
-replace
caveat re ConvertFrom-StringData
是它解释$htValues = ConvertFrom-StringData ($line -replace ' ', "`n")
字符的原因。作为开始的转义序列;例如,诸如\
的值会破坏命令:
b\c
从正面来看,使用Convertfrom-StringData 'a=b\c' # ERROR: "parsing 'b\c' - Missing control character."
比使用ConvertFrom-StringData
进行手动解析要快得多。
顺便说一句:PowerShell的foreach
cmdlet用于一一读取行(默认情况下)很方便,但是慢。
要更快地处理(大)文本文件的行,请使用:
Get-Content
答案 2 :(得分:0)
所以您显示给我的日志的工作方式看起来像我们可以从中剪切和粘贴的三个部分 对象,可以从新行返回 密钥对,可以从空白处返回 密钥,可以通过删除=
返回我使用这种想法为这种情况编写了一个函数
function ConvertTo-PsObjectArrayList($Text,$TextObjectSeparator,$KeyPairSeparator,$KeySeparator){
$ArrayList = New-Object System.Collections.ArrayList
$TestData -split $TextObjectSeparator | %{
$PsObject = new-object System.Management.Automation.PSObject
$_ -split $KeyPairSeparator | %{
$KeyPair = $_ -split $KeySeparator
$PsObject | Add-Member -MemberType NoteProperty -Name $KeyPair[0] -Value $KeyPair[1]
}
$ArrayList.Add($PsObject) | out-null
}
return $ArrayList
}
$TestData = @'
ts=2019-01-16 network=1.1.1.1 system=irgendwas pid=100 bugReq=dasf something=else maybe=this
ts=2019-01-16 network=1.1.2.1 system=irgendwas pid=130 bugReq=dasf something=else
ts=2019-01-16 network=1.1.1.1 system=irgendwas pid=150 bugReq=dasf something=else maybe=this
ts=2019-01-16 network=1.1.1.1 system=irgendwas pid=110 bugReq=dasf something=else
'@
ConvertTo-PsObjectArrayList -Text $TestData -TextObjectSeparator "`r`n" -KeyPairSeparator " " -KeySeparator "=" | select TS, System, Something
这将返回
ts system something
-- ------ ---------
2019-01-16 irgendwas else
2019-01-16 irgendwas else
2019-01-16 irgendwas else
2019-01-16 irgendwas else