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
) 执行所需的匹配。
相反,使用 regex 和 negative 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。
我有一个包含两个字符串之一的文件列表:
"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
) 执行所需的匹配。
相反,使用 regex 和 negative 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。