【发布时间】:2015-08-04 12:23:30
【问题描述】:
有没有办法使用Select-String 来查找X 和Y 之间的所有行。
例如如果我有一个包含内容的文件:
[line 157: Time 2015-08-04 11:34:00]
<staff>
<employee>
<Name>Bob Smith</Name>
<function>management</function>
<age>39</age>
<birthday>3rd June</birthday>
<car>yes</car>
</employee>
<employee>
<Name>Sam Jones</Name>
<function>security</function>
<age>24</age>
</employee>
<employee>
<Name>Mark Perkins</Name>
<function>management</function>
<age>32</age>
</employee>
</staff>
我想找到< function >management< /function > 的所有内容,所以我最终会得到:
<employee>
<Name>Bob Smith</Name>
<function>management</function>
<age>39</age>
<birthday>3rd June</birthday>
<car>yes</car>
</employee>
<employee>
<Name>Mark Perkins</Name>
<function>management</function>
<age>32</age>
</employee>
如果所有分组的大小相同,我可以使用类似:
Select-String -Pattern '<function>management</function>' -CaseSensitive -Context 2,2
但是,实际上它们的大小不会相同,所以我不能每次都使用固定的数字。
真的,我需要一种方式来表示返回所有内容:
2 rows above my search term
until
the following '</employee>' field
对于所有匹配的实例。
这可能吗?
我不能在 powershell 中使用标准的 xml 工具,因为我正在阅读的文件不是标准的 xml,因此我以 [line 157: Time 2015-08-04 11:34:00] 为例。最好的想法是大量的 xml 文件,全部合并到一个 xml 文件中,并使用 [line . . .] 标头将它们分解。
其他信息: 我担心我的例子有点过于简单,实际文件更像:
[line 157: Time 2015-08-04 11:34:00]
<?xml version="1.0" encoding="utf-8"?>
<other>
<stuff>
. . .
</stuff>
</other>
<?xml version="1.0" encoding="utf-8"?>
<staff>
<employee>
...
</employee>
</staff>
<staff>
<employee>
...
</employee>
</staff>
[line End: Time 2015-08-04 11:34:00]
其他信息
我添加了代码以忽略 < ?xml version. . . 行。
我还尝试添加我自己的根元素:
$first = "<open>"
$last = "</open>"
$a = 0
. . .
if($a -eq 0)
{
$XmlFiles[$Index] += $first
$a++
}
. . .
$XmlFiles[$Index] += $last
但这会产生Array assignment failed because index '-1' was out of range. 错误
其他信息 最终结果是这样的:
$FilePath = "C:\Path\To\XmlDocs.txt"
$XmlFiles = @()
$Index = -1
$first = "<open>"
$last = "</open>"
# Go through the file and store the individual xml documents in a string array
$a=0
Get-Content $FilePath | `
%{
if($_ -match "^\[line\ \d+")
{
if($a -eq 0)
{
#if this is the top line, ignore it
}
else
{
#if this is a boundary, add a closing < /open > tag
$XmlFiles[$Index] += $last
}
# We've got a boundary, move to next index in array
$Index++
# Add a new string to hold the next xml document
$XmlFiles += ""
# Add an < open > tag
$XmlFiles[$Index] += $first
$a++
}
elseif ($_ -match '^\<\?xml') #ignore xml headers
{
# End of Section, or XML Header. Do Nothing and move on
}
elseif([string]::IsNullOrEmpty($_))
{
# Blank Line, Do Nothing and move on
}
else
{
# Add each line to the string (xml doesn't care about line breaks)
$XmlFiles[$Index] += $_
}
}
# add the final < /open > tag
$XmlFiles[$Index] += $last
$a=0
$Results = foreach($File in $XmlFiles)
{
$Xml = [xml]($File.Trim())
# Parse string as an Xml document
$Xml = [xml]$File
# Use Xpath to find the manager
$Xml.SelectNodes("//employee[function = 'management']") |% {$_}
$a++
}
$Results
它基本上忽略了标题[line. . .、xml 定义< ?xml 和任何空行,并在每个部分周围添加了< open >. . . < /open > 标记以使其有效。
【问题讨论】:
-
每个文件中是否只有一对
[line ...] [line End ...]?如果是这样,只需丢弃[]行并在遇到空行时增加索引 -
很遗憾没有,添加了许多
[line]对。这基本上是一个日志文件,每隔几分钟就会写入一次。 -
修复损坏的输入文件格式。说真的。
-
我希望我可以,不幸的是我没有构建它。
-
@IGGt 你真的试过更新我的例子中的 if 语句来做
if(($_ -match "^\[line\ \d+") -or [string]::IsNullOrWhiteSpace($_))吗?
标签: xml powershell-2.0 select-string