使用 Select-String 在 powershell 中检查两个 .txt 文件

Using Select-String for checking two .txt files in powershell

我对编写 powershell 脚本完全陌生。到目前为止,我一直在使用普通批处理,因为这是我公司的要求。在此批次中,我使用嵌套的 foor 循环来比较两个 .txt 文件,具体我想执行以下操作:

目的是计算文件1中每个字符串在文件2中出现的次数,例如RMS 被计数 300 次。

由于我以前的代码在 运行 时间方面有一些巨大的缺点(文件 1 有大约 400 行,文件 2 有 500.000 行)我读到 Powershell 的 Select-String 效率更高. 但是,当我正在阅读一些教程时,我不清楚如何在这里继续,除此之外我必须 运行 我的 .bat 中的 powershellcode。 我最大的问题是我不确定如何以及在哪里放置我的 'variables',所以两个输入文件 1 和 2

到目前为止,我正在测试 Select-String 方法,如下所示:

powershell -command "& {Select-String -Path *.txt -Pattern "RMS"}"

我的假设是使用管道,所以像这样:

powershell -command "& {<<path to file one, should read line by line>> | Select-String -Path File2.txt -Pattern "value of file 1"}"

但是,我没有让它工作。 Powershell 在第一个管道之前期待某种 psobject

Select-String 有用,但它并不神奇:)

考虑到性能影响,我会这样处理:

  • 对于 File2 中的每一行:
    • 测试所有项在File1
    • 中的出现

这样,你只需要读取和计算File2 一次:

# prepare hashtable to keep track of count
$count = @{}

# read terms to search for from file1
$termsToFind = Get-Content .\file1 |ForEach-Object {
  $_ -split ';' |Select -Last 1
}

# loop over lines in file2, count the words we're searching for
Get-Content .\test\file2 |ForEach-Object {
  foreach($term in $termsToFind){
    # Using `Regex.Matches()` will help us find multiple occurrences of the same term
    $count[$term] += [regex]::Matches($_,"\b$([regex]::Escape($term))\b").Count
  }
}

现在 $count 将是一个哈希表,其中键是文件 1 中的术语,值是每个单词的计数。

输出格式与 file1 相同:

$count.GetEnumerator() |ForEach-Object { $_.Value,$_.Key -join ';' } |Set-Content output.txt

如果你查看文档,你不能将 -pattern 传递给 select-string。您可以使用括号使某些内容的输出成为模式参数:

powershell select-string -pattern (get-content file1) -path file2    

利用 pattern 是位置 0 和 path 是位置 1 的事实。-pattern 也可以是数组。

powershell select-string (get-content file1) file2  

为了获得最佳性能,我会像这样处理此任务。

  • 读取包含条款的 CSV 文件(它 CSV,带有 ; 分隔符)
  • 将另一个文件读入字符串
  • 对于每个术语,计算它在目标字符串中出现的频率(使用 .IndexOf()

例如

$data = Import-Csv "file1.txt" -Delimiter ";" -Header ID,Term 
$target = Get-Content "file2.txt" -Raw
$counts = @{}

foreach ($term in $data.Term) {
    $index = -1
    $count = 0
    do {
        $index = $target.IndexOf($term, $index + 1)
        if ($index -gt -1) { $count++ } else { break; }
    } while ($true);
    $counts[$term] = $count
}

$counts 

备注

  • Import-Csv 将自动使用输入文件中的第一行作为 header。如果您的文件已经有 header,您可以删除 -Headers 参数。
  • Get-Content 将默认将输入文件读入行数组。但是对于这种方法,将整个文件作为一个大字符串是正确的 - 这就是 -Raw 所做的。
  • @{} 创建一个空哈希表
  • $data.Term 将访问 CSV 的一列
  • .IndexOf() 区分大小写。默认情况下,PowerShell 是 case-insenstive,但像这样的原生 .NET 方法不会改变它们的行为。这可能是也可能不是您需要的 - 如果您不关心大小写,请在 $target$term 上使用 .ToLower()