【问题标题】:Scan txt file for multiple strings and save the following lines扫描 txt 文件中的多个字符串并保存以下行
【发布时间】:2017-08-29 12:26:12
【问题描述】:

我有一个我正在尝试解决的问题,但是,由于我不具备 PowerShell 知识,事实证明它比我希望的要难。所以任何帮助将不胜感激。

问题可以简化为:

  1. 在 txtfile 中查找字符串

  2. 提取该字符串后行的信息

  3. 将信息存储在句柄中

  4. 在 txtfile 中找到第二个字符串并重复该过程

  5. 将这两个字符串存储在一个新文件中或删除 txt 文件中的所有其他内容。

然后我尝试对大约 20k 个文件执行此操作。我希望在他们的关键字和逗号下分隔信息,以便我可以将它们导入其他系统。

我的文件看起来有点像下面

random words 
that are unimportant 
Keyword
FirstlineofNumbersthatIwanttoExtract
random words again that are unimportant 
Secondkeyword
SecondLineOfNumbersThatIWantToExtract
end of the file 

但是,就我要提取的行所在的行而言,所有文件都不相似。我希望输出类似于

Keyword, SecondKeyword
FirstLineOfNumbersThatIWantToExtract, SecondLineOfNumbersThatIWantToExtract

完成了。我已经走到这一步了

 [System.IO.DirectoryInfo]$folder = 'C:\users\xx\Desktop\mappcent3'

 foreach ($file in ($folder.EnumerateFiles())) {
     if ($file.Extension -eq '.txt') {

         $content = Get-Content $file

         $FirstRegex = 'KeyWordOne
    (.+)$'

    $First_output = "\1"
    $test = Select-String -Path $file.FullName -Pattern $FirstRegex 

  }
}

【问题讨论】:

  • 单个文件有多大?
  • 每个文件大约 1-2Kbs,所以它们并不大。
  • 你知道你有什么版本的PowerShell吗? (Get-Host).Version
  • 为什么使用[System.IO.DirectoryInfo] 而不仅仅是Get-ChildItem -Path "C:\Users\xx\Desktop\mappcent3\*.txt"
  • @JeffZeitlin 这肯定是来自互联网的代码位,由于我不具备 powershell 知识

标签: powershell powershell-4.0


【解决方案1】:

这会做一些类似于你问的事情。这需要 PowerShell 3.0+

$path = 'C:\users\xx\Desktop\mappcent3'
$firstKeyword = "Keyword"
$secondKeyword = "Secondkeyword"
$resultsPath = "C:\Temp\results.csv"
Get-ChildItem $path -Filter "*.txt" | ForEach-Object{
    # Read the file in
    $fileContents = Get-Content $_.FullName

    # Find the first keyword data
    $firstKeywordData = ($fileContents | Select-String -Pattern $firstKeyword -Context 0,1 -SimpleMatch).Context.PostContext[0]

    # Find the second keyword data
    $secondKeywordData = ($fileContents | Select-String -Pattern $secondKeyword -Context 0,1 -SimpleMatch).Context.PostContext[0]

    # Create a new object with details gathered. 
    [pscustomobject][ordered]@{
        File = $_.FullName
        FirstKeywordData = $firstKeywordData
        SecondKeywordData = $secondKeywordData
    }

} | Export-CSV $resultsPath -NoTypeInformation

Select-String 是这里最神奇的地方。我们利用了-Context,它在比赛前后消耗了行数。我们想要以下一个,这就是我们使用0,1 的原因。将其包装在自定义对象中,然后我们可以将其导出到 CSV 文件。

关键字重叠

请注意,您的关键字可能会重叠并在输出文件中产生奇怪的结果。在您的示例中,关键字匹配多行,因此结果集将反映这一点。


如果您只是想写回原始文件,您也可以轻松地做到这一点

"$firstKeywordData,$secondKeywordData" | Set-Content $_.FullName

或类似的东西。

【讨论】:

  • 嗨,马特,这看起来很棒。感谢您的帮助。不过,我确实有一些初步的问题。我正在尝试理解代码并因此逐步运行它。我首先为宏变量分配正确的值,然后更改 $fileContents = Get-Content $_.FullName 以指向特定文件。伊朗 $firstKeywordData = (Select-String -Pattern $firstKeyword -Context 0,1 -SimpleMatch).Context.PostContext 但是它没有给我任何东西,也没有停止运行。为什么?如何查看捕获的变量?我在考虑宏的获取内容。
  • 它不会让我再写了,但再次感谢所有帮助
  • 您不应该更改$fileContents = ... 行,这是在循环传递期间读取每个文件的内容。应该只需要更改前几个变量。哎呀。我忘记将数据传递给选择字符串。已更新。
  • @bettingdelo 我添加了另一个更新来解释有时返回的数组。注意选择字符串行末尾的[0]
  • Get-ChildItem $path -Filter "*.txt" | ForEach-Object{ # 读取文件中的 $fileContents = Get-Content $_.FullName # 找到第一个关键字数据 $firstKeywordData = ($fileContents | Select-String -Pattern $firstKeyword -Context 0,1 -SimpleMatch).Context. PostContext # 查找第二个关键字数据 $secondKeywordData = ($fileContents | Select-String -Pattern $secondKeyword -Context 0,1 -SimpleMatch).Context.PostContext # 创建一个收集了详细信息的新对象。 $FirstKeywordData[0] + "," + $SecondKeywordData[0] } > $resultsPath
【解决方案2】:

Select-String cmdlet 有一个-Context 参数,可以轻松提取匹配行之前或之后的行。

您可以使用Export-Csv 导出为您需要的格式(尽管对于 20K 文件,您可能希望直接写入输出文件)

foreach($file in Get-ChildItem C:\users\xx\Desktop\mappcent3 |Where {-not $_.PsIsContainer})
{
    $FirstKeyword = 'FirstKeyword'
    $FirstLine = Select-String -Path $file.FullName -Pattern $FirstKeyword -Context 0,1 |Select -Expand Context -First 1 |Select -Expand PostContext
    $SecondKeyword = 'SecondKeyword'
    $SecondLine = Select-String -Path $file.FullName -Pattern $SecondKeyword -Context 0,1 |Select -Expand Context -First 1 |Select -Expand PostContext

    New-Object psobject -Property @{$FirstKeyword=$FirstLine;$SecondKeyword=$SecondLine} |Export-Csv (Join-Path $file.DirectoryName ($file.BaseName + '_keywords.txt'))
}

【讨论】:

  • 这看起来你的目标是 2.0 兼容性,这很好。如果是这样的话,我会处理 -File 这是 3.0 的东西
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-21
  • 1970-01-01
相关资源
最近更新 更多