下面的 findstr.exe
命令几乎完成了我想要的,但不完全是:
findstr /s /i /c:"word1 word2 word3" *.abc
我用过:
/s
用于搜索所有子文件夹。 /c:
Uses specified text as a literal search string
/i
指定搜索不区分大小写。 *.abc
abc 类型的文件。 上面将
word1 word2 word3
作为字面量查找,因此只能以确切的顺序查找单词。相比之下, 我希望所有单词以任何顺序(AND 逻辑,连词)单独匹配 。
如果我从上面的命令中删除
/c:
,则返回匹配任何单词的行(OR 逻辑、析取),这不是我想要的。这可以在 PowerShell 中完成吗?
最佳答案
您可以使用 Select-String
对多个文件进行基于正则表达式的搜索。
要将单个字符串中的所有多个搜索词与正则表达式匹配,您必须使用 a lookaround assertion :
Get-ChildItem -Filter *.abc -Recurse |Select-String -Pattern '^(?=.*\bword1\b)(?=.*\bword2\b)(?=.*\bword3\b).*$'
在上面的例子中,这是第一个命令发生的事情:
Get-ChildItem -Filter *.abc -Recurse
Get-ChildItem
searches for files in the current directory
-Filter *.abc
shows us only files ending in*.abc
-Recurse
searches all subfolders
然后我们将生成的 FileInfo 对象通过管道传输到
Select-String
并使用以下正则表达式模式:^(?=.*\bword1\b)(?=.*\bword2\b)(?=.*\bword3\b).*$ ^ # start of string (?= # open positive lookahead assertion containing .* # any number of any characters (like * in wildcard matching) \b # word boundary word1 # the literal string "word1" \b # word boundary ) # close positive lookahead assertion ... # repeat for remaining words .* # any number of any characters $ # end of string
由于每个前瞻组只是为了正确性而断言,并且字符串中的搜索位置永远不会改变,因此顺序无关紧要。
如果您希望它匹配包含任何单词的字符串,您可以使用一个简单的非捕获组:
Get-ChildItem -Filter *.abc -Recurse |Select-String -Pattern '\b(?:word1|word2|word3)\b'
\b(?:word1|word2|word3)\b \b # start of string (?: # open non-capturing group word1 # the literal string "word1" | # or word2 # the literal string "word2" | # or word3 # the literal string "word3" ) # close positive lookahead assertion \b # end of string
这些当然可以在 a simple proxy function 中抽象出来。
我生成了
param
块和下面的 Select-Match
函数定义的大部分主体:$slsmeta = [System.Management.Automation.CommandMetadata]::new((Get-Command Select-String))
[System.Management.Automation.ProxyCommand]::Create($slsmeta)
然后删除不必要的参数(包括
-AllMatches
和 -Pattern
),然后添加模式生成器(请参阅内联注释):function Select-Match
{
[CmdletBinding(DefaultParameterSetName='Any', HelpUri='http://go.microsoft.com/fwlink/?LinkID=113388')]
param(
[Parameter(Mandatory=$true, Position=0)]
[string[]]
${Substring},
[Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
[Alias('PSPath')]
[string[]]
${LiteralPath},
[Parameter(ParameterSetName='Any')]
[switch]
${Any},
[Parameter(ParameterSetName='Any')]
[switch]
${All},
[switch]
${CaseSensitive},
[switch]
${NotMatch},
[ValidateNotNullOrEmpty()]
[ValidateSet('unicode','utf7','utf8','utf32','ascii','bigendianunicode','default','oem')]
[string]
${Encoding},
[ValidateNotNullOrEmpty()]
[ValidateCount(1, 2)]
[ValidateRange(0, 2147483647)]
[int[]]
${Context}
)
begin
{
try {
$outBuffer = $null
if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
{
$PSBoundParameters['OutBuffer'] = 1
}
# Escape literal input strings
$EscapedStrings = foreach($term in $PSBoundParameters['Substring']){
[regex]::Escape($term)
}
# Construct pattern based on whether -Any or -All was specified
if($PSCmdlet.ParameterSetName -eq 'Any'){
$Pattern = '\b(?:{0})\b' -f ($EscapedStrings -join '|')
} else {
$Clauses = foreach($EscapedString in $EscapedStrings){
'(?=.*\b{0}\b)' -f $_
}
$Pattern = '^{0}.*$' -f ($Clauses -join '')
}
# Remove the Substring parameter argument from PSBoundParameters
$PSBoundParameters.Remove('Substring') |Out-Null
# Add the Pattern parameter argument
$PSBoundParameters['Pattern'] = $Pattern
$wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Utility\Select-String', [System.Management.Automation.CommandTypes]::Cmdlet)
$scriptCmd = {& $wrappedCmd @PSBoundParameters }
$steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
$steppablePipeline.Begin($PSCmdlet)
} catch {
throw
}
}
process
{
try {
$steppablePipeline.Process($_)
} catch {
throw
}
}
end
{
try {
$steppablePipeline.End()
} catch {
throw
}
}
<#
.ForwardHelpTargetName Microsoft.PowerShell.Utility\Select-String
.ForwardHelpCategory Cmdlet
#>
}
现在你可以像这样使用它,它的行为几乎像
Select-String
:Get-ChildItem -Filter *.abc -Recurse |Select-Match word1,word2,word3 -All
关于powershell - 如何在 PowerShell 中使用 FINDSTR 查找搜索字符串中所有单词以任何顺序匹配的行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43450914/