解析文本文件并写出数据
Posted
技术标签:
【中文标题】解析文本文件并写出数据【英文标题】:Parse through text file and write out data 【发布时间】:2013-02-21 18:26:56 【问题描述】:我正在着手创建一个将读取打印机日志(可能使用 get-WMI cmdlet)并解析日志的 powershell 脚本的第一步。之后,我计划将脚本输出到 .txt 文件中,包括打印机名称、打印机使用次数计数器(如果可能)以及日志中的具体信息。
为了做到这一点,我决定尝试倒退。下面是日志的一小部分:
10 Document 81, A361058/GPR0000151814_1: owned by A361058 was printed on R3556 via port IP_***.***.***.***. Size in bytes: 53704; pages printed: 2 20130219123105.000000-300
10 Document 80, A361058/GPR0000151802_1: owned by A361058 was printed on R3556 via port IP_***.***.***.***. Size in bytes: 53700; pages printed: 2
向后工作并首先专注于解析,我希望能够专门获取“/GRP”、“R3446(通常为 R**,因为这是打印机名称)”,并获得一个计数器,显示特定打印机在日志文件中出现的频率。
自从我上次使用 Powershell 以来已经有一段时间了,但目前这是我为了尝试实现我的目标而设法创建的:
Select-String -Path "C:\Documents and Settings\a411882\My Documents\Scripts\Print Parse Test.txt" -Pattern "/GPR", " R****" -AllMatches -SimpleMatch
代码不会产生任何错误,但是我也无法让任何输出出现在屏幕上以查看我是否正在捕获 /GRP 和打印机名称。目前,我正在尝试确保在担心任何计数器之前收集正确的输出。谁能帮助我并告诉我我的代码做错了什么?
谢谢!
编辑:修复了我的代码导致屏幕上没有数据出现的一个小错误。目前,此代码输出整行两行测试文本,而不是仅输出 /GPR 和服务器名称。新的输出如下:
My Documents\Scripts\Print Parse Test.txt:1:10 Document 81, A361058/GPR0000151814_1: owned by A361058 was printed on
R3556 via port IP_***.***.***.***. Size in bytes: 53704; pages printed: 2
20130219123105.000000-300
My Documents\Scripts\Print Parse Test.txt:2:10 Document 80, A361058/GPR0000151802_1: owned by A361058 was printed on
R3556 via port IP_***.***.***.***. Size in bytes: 53700; pages printed: 2
我想尝试让它最终看起来像下面这样:
/GPR, R****, count: ## (although for now I'm less concerned about the counter)
【问题讨论】:
删除Write-Host |
。您不能将一个空命令流水线化到另一个命令中。 Select-String
会自己输出结果
Graimer:我最初尝试不使用 write-host,但是每当我这样做时,我也没有显示任何输出,所以我认为我必须在某些方法中使用 Write-Host
如果select-string
没有返回任何对象,那是因为它没有找到任何东西。它没有找到任何东西的原因是因为你拼错了“GPR”。 “/GRP” 不是“/GPR” :-)
啊哈!!我知道我错过了一些愚蠢的东西,但只是看不到它 =P 现在我正在获取信息,但是目前它只是重写了整个 2 行测试 txt。我现在只想输出 /GPR 和服务器名称
【参考方案1】:
你可以试试这个。它仅在存在/GPR
(以及“printed on”中的“on”)存在时返回一行。
Get-Content .\test.txt | %
if ($_ -match '(?:.*)(/GPR)(?:.*)(?<=on\s)(\w+)(?:.*)')
$_ -replace '(?:.*)(/GPR)(?:.*)(?<=on\s)(\w+)(?:.*)', '$1,$2'
输出:
/GPR,R3556
/GPR,R3556
我确信有更好的正则表达式版本。我还在学习它:-)
EDIT这更容易阅读。正则表达式仍然可以提取,但我首先使用 select-string
过滤掉带有 /GPR 的行:
Get-Content .\test.txt | Select-String -SimpleMatch -AllMatches -Pattern "/GPR" | %
$_.Line -replace '(?:.*)(/GPR)(?:.*)(?<=on\s)(\w+)(?:.*)', '$1,$2'
【讨论】:
哦哇...正则表达式..如果要求不高,您能解释一下代码吗?我从未见过如此大量基于正则表达式编写的 powershell。这是我认为它正在做的事情,想知道您是否可以纠正我,以便我理解代码: 它正在搜索 /GPS 并且搜索“on”之后的单词,“on\s”可能是“on”,“\w+”可能表示下一个单词,我不确定我是否理解然而,'$1,$2' 是存在的。 括号内的东西是一组。有些正在捕获(存储价值),有些则没有。第一组匹配下一组(/GPR)之前的所有内容并将其丢弃。第二个匹配 /GPR 并保留它。第三个等于第一个。然后我搜索“on”并将其丢弃(只是为了搜索带有 R3556 的位置)。然后我得到下一个单词(即 R3556)并保留它,然后它与该行的其余部分匹配。由于该行中的所有内容都匹配,因此所有内容都将替换为我指定的内容。我指定了 '$1,$2' 这意味着我用逗号保留的 2 个组。很难解释简短:P 我添加了另一个示例,它首先使用select-string
查找带有“/GPR”的字符串,然后仅使用正则表达式进行提取。它更漂亮:)
在使用了您编写代码的方法并稍作修改之后,我想我开始了解它是如何工作的。 :) 如果我想添加更多我想要搜索的东西(例如另一个是 DEV),那么我只需要添加 (?:.*)(DEV)(?:.*) 和 $3 吗?跨度>
【参考方案2】:
我通常从我正在匹配的行的示例开始,并从中构建一个正则表达式,用正则表达式元字符替换文本的可变部分。这使得正则表达式更长,但以后阅读起来更直观。
将正则表达式分配给一个变量,然后在后续代码中使用该变量,以防止正则表达式的混乱细节弄乱其余代码:
[regex]$DocPrinted =
'Document \d\d, \w+/(\D3)[0-9_]+: owned by \w+ was printed on (\w+) via port IP_[0-9.]+ Size in bytes: \d+; pages printed: \d+'
get-content <log file> |
foreach
if ($_ -match $DocPrinted)
$line -match $docprinted > $null
$matches
【讨论】:
以上是关于解析文本文件并写出数据的主要内容,如果未能解决你的问题,请参考以下文章
如何解析具有特定格式数据的文本文件并使用 perl 将其存储在哈希中
C 语言文件操作 ( 配置文件读写 | 写出或更新配置文件 | 逐行遍历文件文本数据 | 获取文件中的文本行 | 查询文本行数据 | 追加文件数据 | 使用占位符方式拼接字符串 )