Ray*_*ker 3 powershell boolean-logic findstr
以下findstr.exe
命令几乎可以实现我想要的功能,但并不完全:
findstr /s /i /c:"word1 word2 word3" *.abc
Run Code Online (Sandbox Code Playgroud)
我用过:
/s
用于搜索所有子文件夹./c:
使用指定的文本作为文字搜索字符串
/i
指定搜索不区分大小写.*.abc
abc类型的文件.上述验看word1 word2 word3
作为文字,因此只发现在的话,准确的顺序.
相比之下,我想所有的字匹配个别,在任何顺序(与逻辑,结合).
如果我/c:
从上面的命令中删除,那么返回匹配任何单词的行(OR逻辑,析取),这不是我想要的.
可以在PowerShell中完成吗?
您可以使用Select-String
通过多个文件进行基于正则表达式的搜索.
要将单个字符串中的所有多个搜索项与正则表达式匹配,您必须使用外观断言:
Get-ChildItem -Filter *.abc -Recurse |Select-String -Pattern '^(?=.*\bword1\b)(?=.*\bword2\b)(?=.*\bword3\b).*$'
Run Code Online (Sandbox Code Playgroud)
在上面的例子中,这是第一个命令发生的事情:
Run Code Online (Sandbox Code Playgroud)Get-ChildItem -Filter *.abc -Recurse
Get-ChildItem
搜索当前目录
-Filter *.abc
中的文件只显示以*.abc
-Recurse
搜索所有子文件夹结尾的文件
然后,我们将生成的FileInfo对象传递给Select-String
并使用以下正则表达式模式:
Run Code Online (Sandbox Code Playgroud)^(?=.*\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'
Run Code Online (Sandbox Code Playgroud)
Run Code Online (Sandbox Code Playgroud)\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
这些当然可以通过简单的代理功能抽象出来.
我生成了param
块和Select-Match
下面函数定义的大部分主体:
$slsmeta = [System.Management.Automation.CommandMetadata]::new((Get-Command Select-String))
[System.Management.Automation.ProxyCommand]::Create($slsmeta)
Run Code Online (Sandbox Code Playgroud)
然后删除不必要的参数(包括-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
#>
}
Run Code Online (Sandbox Code Playgroud)
现在你可以像这样使用它,它的行为几乎就像Select-String
:
Get-ChildItem -Filter *.abc -Recurse |Select-Match word1,word2,word3 -All
Run Code Online (Sandbox Code Playgroud)
另一种(公认不太复杂的)方法是简单的菊花链滤波器,因为单词的顺序无关紧要。过滤您的文件一个字,然后再过滤输出也包含第二个单词,然后过滤线是输出线也拥有这个第三个单词。
findstr /s /i "word1" *.abc | findstr /i "word2" | findstr /i "word3"
Run Code Online (Sandbox Code Playgroud)
使用 PowerShell cmdlet 上面的内容如下所示:
Get-ChildItem -Filter '*.abc' -Recurse | Get-Content | Where-Object {
$_ -like '*word1*' -and
$_ -like '*word2*' -and
$_ -like '*word3*'
}
Run Code Online (Sandbox Code Playgroud)
或(使用别名):
ls '*.abc' -r | cat | ? {
$_ -like '*word1*' -and
$_ -like '*word2*' -and
$_ -like '*word3*'
}
Run Code Online (Sandbox Code Playgroud)
请注意,别名只是为了节省在命令行上输入的时间,因此我不建议在脚本中使用它们。
归档时间: |
|
查看次数: |
1700 次 |
最近记录: |