我有一个包含两个字符串之一的文件列表:
"stuff
"或";stuff
">
我正在尝试编写一个PowerShell脚本,该脚本将仅返回包含"stuff
"的文件。下面的脚本目前返回所有文件,因为显然"stuff
"是";stuff
"的子字符串
。对于我的一生,我无法弄清楚如何只匹配包含"stuff
"的文件,而没有前面的;
Get-Content "C:templistlist.txt" |
Where-Object { Select-String -Quiet -Pattern "stuff" -SimpleMatch $_ }
注意:C:templistlist.txt
包含每个文件路径传递给Select-String
的文件路径列表。
感谢您的帮助。
您无法使用文本子字符串搜索 (-SimpleMatch
) 执行所需的匹配。
相反,使用带有否定后视断言((?<!..)
) 的正则表达式来排除前面有;
字符的stuff
子字符串:(?<!;)stuff
应用于您的命令:
Get-Content "C:templistlist.txt" |
Where-Object { Select-String -Quiet -Pattern '(?<!;)stuff' -LiteralPath $_ }
正则表达式陷阱:
使用否定(
^
)字符集([...]
)是很诱人的[^;]stuff
(见此答案);但是,如果stuff
出现在一行的最开头,这将不能按预期工作,因为字符集 - 无论是否否定 - 仅匹配实际字符,而不是行首位置。然后,很容易将
?
应用于否定的字符集(对于可选匹配 - 出现 0 或 1):[^;]?stuff
。但是,这将再次匹配包含;stuff
的字符串,因为stuff
在技术上前面是否定字符集的"0 重复出现";因此,';stuff' -match '[^;]?stuff'
产生$true
。
在这种情况下,只有后视断言才能正常工作 - 请参阅 regular-expressions.info。
为了补充@mklement0的答案,我建议使用另一种方法来使您的代码更易于阅读和理解:
#requires -Version 4
@(Get-Content -Path 'C:Templistlist.txt').
ForEach([IO.FileInfo]).
Where({ $PSItem | Select-String -Pattern '(?<!;)stuff' -Quiet })
这会将您的字符串转换为对象(System.IO.FilePath
),并利用数组函数ForEach
和Where
来简洁。 此外,这允许您将路径作为对象通过管道传输,这些对象将被-Path
参数接受到Select-String
中,以使其更易于理解(我发现长长的参数集列表难以阅读)。
发布的示例代码实际上不会运行,因为它会将每一行视为-Path
值。
您需要的是获取内容,选择所需的字符串,然后使用Where-Object
筛选结果
Get-Content "C:templistlist.txt" | Select-String -Pattern "stuff" | Where-Object {$_ -notmatch ";stuff"}
如果需要,您可以创建一个更复杂的正则表达式,但这取决于文件中的结果数据的外观