使用选择字符串检查powershell中的两个.txt文件

使用选择字符串检查powershell中的两个.txt文件,powershell,command-line,select-string,Powershell,Command Line,Select String,我是全新的编写powershell脚本的人。到目前为止,我使用的是纯批为我的目的,因为这是我的公司的要求。在这个批处理中,我使用嵌套的foor循环对两个.txt文件进行比较,具体来说,我希望执行以下操作: 文件1包含许多字符串。每个字符串在一个单独的行中,前面有一个数字和分号,如:658;RMS 文件2是一些长文本。 目的是统计文件2中文件1中每个字符串的出现次数,例如RMS计数300次 在我之前的代码中,关于运行时文件1有大约400行,文件2有500.000行,我读到Powershell中的S

我是全新的编写powershell脚本的人。到目前为止,我使用的是纯批为我的目的,因为这是我的公司的要求。在这个批处理中,我使用嵌套的foor循环对两个.txt文件进行比较,具体来说,我希望执行以下操作:

文件1包含许多字符串。每个字符串在一个单独的行中,前面有一个数字和分号,如:658;RMS 文件2是一些长文本。 目的是统计文件2中文件1中每个字符串的出现次数,例如RMS计数300次

在我之前的代码中,关于运行时文件1有大约400行,文件2有500.000行,我读到Powershell中的Select字符串效率更高。 然而,由于我正在阅读一些教程,我不清楚如何在这里继续,除此之外,我还必须在.bat中运行powershellcode。 我最大的问题是我不确定如何以及在哪里放置我的“变量”,所以两个输入文件1和2

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

powershell-命令&{Select String-Path*.txt-Pattern RMS}

我的假设是利用管道,所以如下所示:

powershell-命令&{选择字符串-路径File2.txt-文件1的模式值}

然而,我并没有让它发挥作用。Powershell在第一根管道之前正在挖掘某种psobject

选择字符串很有用,但它并不神奇:

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

对于文件2中的每一行: 测试文件1中所有术语的出现情况 这样,您只需读取和评估文件2一次:

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

输出为与文件1相同的格式,包括:

选择字符串很有用,但它不是魔术:

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

对于文件2中的每一行: 测试文件1中所有术语的出现情况 这样,您只需读取和评估文件2一次:

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

输出为与文件1相同的格式,包括:


如果您检查文档,就不能使用管道模式来选择字符串。您可以使用括号将某些内容的输出变为模式参数:

powershell select-string -pattern (get-content file1) -path file2    
使用模式是位置0,路径是位置1这一事实-模式也可以是数组

powershell select-string (get-content file1) file2  

如果您检查文档,就不能使用管道模式来选择字符串。您可以使用括号将某些内容的输出变为模式参数:

powershell select-string -pattern (get-content file1) -path file2    
使用模式是位置0,路径是位置1这一事实-模式也可以是数组

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 
注释

导入Csv将自动使用输入文件中的第一行作为标题。如果您的文件已经有一个头,您可以删除-Headers参数。 默认情况下,“获取内容”将把输入文件读入一个行数组。但是对于这种方法,将整个文件作为一个大字符串是正确的-这就是-Raw所做的。 @{}创建一个空哈希表 $data.Term将访问CSV的一列 .IndexOf区分大小写。默认情况下,PowerShell是case-instate,但是像这样的本机.NET方法不会改变它们的行为。这可能是您所需要的,也可能不是您所需要的-使用。如果您不关心案例,请降低$target和$term。
为了获得最佳性能,我将这样处理此任务

将带有术语的文件读取为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 
注释

导入Csv将自动使用输入文件中的第一行作为标题。如果您的文件已经有一个头,您可以删除-Headers参数。 默认情况下,“获取内容”将把输入文件读入一个行数组。但是对于这种方法,将整个文件作为一个大字符串是正确的-这就是-Raw所做的。 @{}创建一个空哈希表 $data.Term将访问CSV的一列 .IndexOf区分大小写。默认情况下,PowerShell是case-instate,但是像这样的本机.NET方法不会改变它们的行为。这可能是您所需要的,也可能不是您所需要的-使用。如果您不关心案例,请降低$target和$term。
很好,但是你忘了,file1的内容是CSV,比如658;RMS,他只需要第二列。@T-Me谢谢你发现了它,完全忘记了那部分:非常感谢@MathiasR.Jessen我测试了第一部分,你在文件1中读到了,这很好用
我很好。然而,试图弹劾第二部分在一些错误案例中失败。发生这种情况是因为我无法运行外部powershell脚本,所以试图将整个代码放在一行中?我的代码如下所示:powershell-command&{$count=@{};$termsToFind=Get Content'ModulID.txt'| ForEach Object{$\uu-split';| Select-Last 1};Get Content'TlsTrace.prn'| ForEach Object{ForEach$term in$termsToFind{$count[$term]+=[regex]::Matches$\ub$[regex]::Escape$term\b.count}我将文件名更改为真实的文件名,其他方面是相同的,我强烈建议将代码放在.ps1脚本文件中,然后运行powershell-文件C:\path\to\script.ps1,或者将其转换为nice,但您忘记了,文件1的内容类似于CSV 658;RMS,他只需要第二列。@T-Me谢谢你发现了它,完全忘记了那部分:非常感谢@MathiasR.Jessen我测试了第一部分,你在文件1中读到的内容,效果非常好。然而,试图弹劾第二部分在一些错误案例中失败。发生这种情况是因为我无法运行外部powershell脚本,所以试图将整个代码放在一行中?我的代码如下所示:powershell-command&{$count=@{};$termsToFind=Get Content'ModulID.txt'| ForEach Object{$\uu-split';| Select-Last 1};Get Content'TlsTrace.prn'| ForEach Object{ForEach$term in$termsToFind{$count[$term]+=[regex]::Matches$\ub$[regex]::Escape$term\b.count}我将文件名更改为真实的文件名,其他方面是相同的。我强烈建议将代码放在.ps1脚本文件中,然后运行powershell-文件C:\path\to\script.ps1,或者将其转换为我测试过的方法,而且速度非常快:。是否有一些简单的修改,使其只保存计数大于零到$counts的条款?此外,我必须用正则表达式修改搜索表达式,使其只计算精确匹配。由于我不熟悉powershell,在您的代码中添加此项的正确点在哪里?是否有一些简单的修改,以便它只保存计数高于零到$counts的条款?是的,有,我相信您会找到它。这并不难我必须用正则表达式修改搜索表达式,使其只计算精确匹配项。-嗯?上面的代码只计算精确匹配。正则表达式适用于不需要精确匹配的情况。哦,好吧,我忘了提到很多,对此表示抱歉。在我的文件2中有几行。例如,我想计算“RM4”的出现次数,现在可以存在以下行:123456789 RM4 987654321->应计为1,但是,这一行中出现的情况不应计算在内:12345 RM4.DLL 9876所以我的目标是将搜索词封装在空白处,这样后面就不会有任何其他内容了:太好了,我会尽我最大的努力谢谢你的帮助,确实这应该不那么困难。好的,第一件事很简单。我理解你的代码,你的方法非常聪明。我现在添加了if$count-gt 0{$counts[$term]=$count},并用它替换了$counts[$term]=$count,我还测试了您的方法,它非常快:。是否有一些简单的修改,使其只保存计数大于零到$counts的条款?此外,我必须用正则表达式修改搜索表达式,使其只计算精确匹配。由于我不熟悉powershell,在您的代码中添加此项的正确点在哪里?是否有一些简单的修改,以便它只保存计数高于零到$counts的条款?是的,有,我相信您会找到它。这并不难我必须用正则表达式修改搜索表达式,使其只计算精确匹配项。-嗯?上面的代码只计算精确匹配。正则表达式适用于不需要精确匹配的情况。哦,好吧,我忘了提到很多,对此表示抱歉。在我的文件2中有几行。例如,我想计算“RM4”的出现次数,现在可以存在以下行:123456789 RM4 987654321->应计为1,但是,这一行中出现的情况不应计算在内:12345 RM4.DLL 9876所以我的目标是将搜索词封装在空白处,这样后面就不会有任何其他内容了:太好了,我会尽我最大的努力谢谢你的帮助,确实这应该不那么困难。好的,第一件事很简单。我理解你的代码,你的方法非常聪明。我现在添加了if$count-gt 0{$counts[$term]=$count},并用这个替换了$counts[$term]=$count