如何在Powershell中过滤掉两次文本?

时间:2018-03-20 13:49:58

标签: powershell scripting

我有一个Powershell脚本返回了一个接近我想要的输出,但是我需要删除一些行和HTML样式的标记。我已经有以下代码来过滤掉:

get-content "atxtfile.txt" | select-string -Pattern '<fields>' -Context 1

但是,如果我尝试将该输出传输到第二个"select-string",我将不会得到任何结果。我在网上查看了REGEX示例,但我见过的大部分内容都涉及使用编码循环来实现其目标。我更习惯于Linux shell,你可以将输出管道输出到多个greps来过滤掉文本。有没有办法用PowerShell实现相同的东西或类似的东西?这是我正在按要求使用的文件:

<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.force.com/2006/04/metadata">
<actionOverrides>
    <actionName>Accept</actionName>
    <type>Default</type>
</actionOverrides>
<actionOverrides>
    <actionName>CancelEdit</actionName>
    <type>Default</type>
</actionOverrides>
   <actionOverrides>
    <actionName>Today</actionName>
    <type>Default</type>
</actionOverrides>
<actionOverrides>
    <actionName>View</actionName>
    <type>Default</type>
</actionOverrides>
<compactLayoutAssignment>SYSTEM</compactLayoutAssignment>
<enableFeeds>false</enableFeeds>
<fields>
    <fullName>ActivityDate</fullName>
</fields>
<fields>
    <fullName>ActivityDateTime</fullName>
</fields>
<fields>
    <fullName>Guid</fullName>
</fields>
<fields>
    <fullName>Description</fullName>
</fields>
</CustomObject>

所以,我只希望<fullName>描述符之间的文本到目前为止我有以下内容:

get-content "txtfile.txt" | select-string -Pattern '<fields>' -Context 1

这将为我提供<fields>描述符之间的所有内容,但是我基本上需要没有XML标记的<fullName>行。

3 个答案:

答案 0 :(得分:2)

最简单的 PSv3 +解决方案使用PowerShell的内置XML DOM支持,这使得XML文档的节点可作为对象层次结构访问 点符号

PS> ([xml] (Get-Content -Raw txtfile.txt)).CustomObject.fields.fullName
ActivityDate
ActivityDateTime
Guid
Description    

请注意即使.fields数组 - 代表顶级元素<fields>的所有子<CustomObject>元素 - .fullName,应用于它并将所有数组元素(<fullName>元素)中的子元素<field> 的值作为数组返回。

能够访问集合上的属性并将其隐式应用于集合的元素,并将结果收集到数组,是一个名为member enumeration的通用PSv3 +功能。

作为替代,请考虑使用 Select-Xml cmdlet (也可在PSv2中使用),支持XPath queries 通常允许更复杂的提取逻辑(虽然这里不是严格要求的); Select-Xml是围绕[xml] .NET类型.SelectNodes() method的高级包装器。 以下是上述解决方案的等效内容:

$namespaces = @{ ns="http://soap.force.com/2006/04/metadata" }
$xpathQuery = '/ns:CustomObject/ns:fields/ns:fullName'
(Select-Xml -LiteralPath txtfile.txt $xpathQuery -Namespace $namespaces).Node.InnerText

注意:

与点符号不同,使用Select-Xml 时必须考虑 XML命名空间

鉴于<CustomObject>及其所有后代都在名称空间xmlns中,通过URI http://soap.force.com/2006/04/metadata标识,您必须:

  • 在您传递的哈希表中定义此命名空间作为-Namespace参数
    • 警告:默认命名空间xmlns的特殊之处在于不能用作哈希表中的键;相反,选择任意键名称,例如ns,但请务必使用所选键名作为节点名称前缀(参见下一点)。
  • 使用命名空间名称后跟: ,为XPath查询中的所有节点名称添加前缀;例如,ns:CustomObject

答案 1 :(得分:1)

确定。所以,如果你有那个文件,那么:

[xml]$xml = Get-Content atextfile.txt
$xml.CustomObject.fields | select fullname

答案 2 :(得分:1)

mklement0为问题提供了最佳解决方案。 但要回答有关使用Select-String过滤文本两次的问题。

如果我们将Select-String的结果导入Out-String -Stream,我们可以再次将其传递给Select-String。 这可以在一行上完成,但我使用变量来尝试使其更具可读性。

$Match = Get-Content "atxtfile.txt" | Select-String -Pattern '<fields>' -Context 1
$Match | Out-String -Stream  | Select-String -Pattern "Guid"

如果我们将$match传递给Get-Member,我们会发现一些有趣的属性。

$Match.Matches.Value

这将显示<fields>的所有实例(模式匹配)。

$Matches.Context.PostContext
$Matches.Context.PreContext

这将包含<fields>之前和之后的行(前后的上下文)。