提取特定数据

时间:2014-07-25 16:18:20

标签: powershell

请帮忙。我试图从以下.xml文件中提取多个文件名。然后,我需要将文件列表从一个文件夹复制到另一个文件夹。我在下面发布的XML的一部分:


   <component>
    <altname>HP Broadcom Online Firmware Upgrade Utility for VMware 5.x</altname>
    <filename>CP021404.scexe</filename>
    <name>HP Broadcom Online Firmware Upgrade Utility for VMware 5.x</name>
    <description>This package contains vSphere 5.1 and VMware  </description>
    <component> 
    <component>
    <altname>Online ROM Flash - Power Management Controller </altname>
    <filename>CP021615.scexe</filename>  

我使用了如下的Windows PowerShell并获得了输出,但输出包含文件名(CP021404.scexe,CP021614.scexe如下),行#和符号仍在其中。我第一次PS尝试时做错了什么?

PowerShell的

   $input_path = ‘C:\PowerShell\hpsum_inventory.xml’
   $output_file = ‘C:\powershell\hpsum_inventory-o.xml’
   $regex = ".exe"
   select-string -Path $input_path -Pattern $regex -AllMatches  > $output_file

输出

PowerShell\hpsum_inventory.xml:8:        <filename>CP021404.scexe</filename>
PowerShell\hpsum_inventory.xml:18:        <filename>CP021614.scexe</filename>

1 个答案:

答案 0 :(得分:0)

问题是你正在使用RegEx匹配并且RegEx中的句点字符匹配除换行符/换行符之外的任何字符,因此它匹配任何字符后跟'exe'。您真正想要做的是将文件读取为XML,然后输出<filename>个节点。

$input_path = ‘C:\PowerShell\hpsum_inventory.xml’
$output_file = ‘C:\powershell\hpsum_inventory-o.xml’
$regex = "exe$"
(Select-Xml -Path $input_path -XPath //filename).node.InnerText | ?{$_ -match $regex} | out-file $output_file

编辑:好的,您需要将其合并到一个字符串中,这很容易。我们将在最后一行添加一个ForEach循环(我使用别名%),将文件名插入到字符串中。

(Select-Xml -Path $input_path -XPath //filename).node.InnerText | ?{$_ -match $regex} | %{"copy c:\powershell\$_ x:\firmware\"} | out-file $output_file

编辑2:好的,所以您需要了解如何匹配文件中文本的一般知识。可以做!选择字符串将实际执行您想要的操作,它对于您之前提供的示例而言通常不是最佳方法。这会变得更有趣,因为你需要熟悉RegEx匹配模式,但除此之外它还相当直接。你想再次使用-Pattern匹配,但让我建议一个更好的模式:

“文件名&GT;(。*?)&LT;”

查找文件名标签,包括关闭&gt;在它上面,抓住一切到下一个&lt;字符。 ()表示捕获组,因此在捕获时会忽略其余组。然后我们管道到一个ForEach循环,对于它找到匹配的每一行,我们选择Matches属性,然后选择第二个Group属性(第一个包含整个文本,包括文件名&gt;和&lt; bits)。所以它看起来像这样:

$input_path = 'C:\PowerShell\hpsum_inventory.xml'
$output_file = 'C:\powershell\hpsum_inventory-o.xml'
$regex = "filename>(.*?)<"
select-string -Path $input_path -Pattern "filename>(.*?)<"|%{$_.matches.groups[1].value}

现在只获取文件名。如果我们想要将其余部分内容添加到文本中,则将该部分包含在子表达式$()内的ForEach循环中,然后将其放入双引号字符串中,如下所示:

select-string -Path $input_path -Pattern "filename>(.*?)<"|%{"copy c:\powershell\$($_.matches.groups[1].value) x:\firmware"}|Out-File $output_file

我个人建议不要直接这样做因为它限制了你。我会在一个数组中收集数据,然后将该数组传输到一个完成你想要的过程,但至少你有这个集合,所以你可以用它做你想要的。

$input_path = 'C:\PowerShell\hpsum_inventory.xml'
$output_file = 'C:\powershell\hpsum_inventory-o.xml'
$regex = "filename>(.*?)<"
$Filenames = select-string -Path $input_path -Pattern "filename>(.*?)<"|%{$_.matches.groups[1].value}
$Filenames|%{"copy c:\powershell\$_ x:\firmware"}|Out-File $output_file

为什么这样?如果你不想写一些东西怎么办?然后你可以做类似的事情:

$Filenames|?{$_ -notin (GCI X:\firmware -file|select -expand name)}|%{"copy c:\powershell\$_ x:\firmware"}|Out-File $output_file

对于序列号的集合,请尝试以下正则表达式模式:

“序列号:(\ S *)”

在RegEx中,有一些具有特殊含义的转义字符,并且将它们大写反转意义。 \ s表示空格,所以空格,制表符,什么不是。把它当作资本意味着不是空白的东西。但是,星号表示它可以找到许多以前的东西(不是空白)。因此,这会查找“序列号:”,然后在此之后捕获所有内容,直到它到达行尾或遇到空白。查看 this link ,看看它是如何运作的。

相关问题