Select-String:仅当字符串前面没有特定字符时才匹配该字符串

Select-String: match a string only if it isn't preceded by a specific character

我有一个包含两个字符串之一的文件列表:

"stuff" 或 ";stuff"

我正在尝试编写一个 PowerShell 脚本,它将 return 仅包含包含“stuff”的文件。下面的脚本当前 returns all 文件,因为显然“stuff”是“;stuff

的子字符串

对于我来说,我无法弄清楚如何只匹配包含“stuff”的文件,而没有前面的 ;

Get-Content "C:\temp\list\list.txt" |
  Where-Object { Select-String -Quiet -Pattern "stuff" -SimpleMatch $_ }

注意:C:\temp\list\list.txt 包含一个文件路径列表,每个路径都传递给 Select-String

感谢您的帮助。

发布的示例代码实际上不会 运行,因为它将每一行视为 -Path 值。

你需要的是获取内容,select你想要的字符串,然后用Where-Object

过滤结果
Get-Content "C:\temp\list\list.txt" | Select-String -Pattern "stuff" | Where-Object {$_ -notmatch ";stuff"}

如果需要,您可以创建更复杂的正则表达式,但这取决于文件中的结果数据是什么样的

为了补充@mklement0 的回答,我建议使用一种替代方法来使您的代码更易于阅读和理解:

#requires -Version 4
@(Get-Content -Path 'C:\Temp\list\list.txt').
    ForEach([IO.FileInfo]).
    Where({ $PSItem | Select-String -Pattern '(?<!;)stuff' -Quiet })

这会将您的字符串转换为对象 (System.IO.FilePath) 并使用数组函数 ForEach and Where for brevity/conciseness。此外,这允许您将路径 作为对象 将被 -Path 参数接受为 Select-String 以使其更易于理解(我发现长列表参数集难以阅读)。

您无法通过 文字 子字符串搜索 (-SimpleMatch) 执行所需的匹配。

相反,使用 regexnegative look-behind assertion ((?<!..)) 排除前面有 ; 字符的 stuff 子串:(?<!;)stuff

应用于您的命令:

Get-Content "C:\temp\list\list.txt" | 
  Where-Object { Select-String -Quiet -Pattern '(?<!;)stuff' -LiteralPath $_ }

正则表达式陷阱:

  • 使用[^;]stuff代替,使用否定(^)字符集([...] )(参见 this answer);但是,如果 stuff 出现在行的 最开头 ,这将 不会 按预期工作,因为字符集 - 是否被否定或不匹配 - 仅匹配实际的 字符 ,而不匹配行首 位置 .

  • 然后将 ? 应用于否定字符集(对于 可选 匹配 - 0 或 1 次出现):[^;]?stuff。但是,这将再次匹配包含 ;stuff 的字符串,因为 stuff 在技术上 前面是否定字符集的“0 次重复出现”;因此,';stuff' -match '[^;]?stuff' 产生 $true.

在这种情况下,只有后视 断言 才能正常工作 - 请参阅 regular-expressions.info