PowerShell 下的 grep —— Select-String 详解及二者对比
使用 help Select-String -ShowWindow
命令我们可以很容易的得到一份中文的帮助文档,其中有这样两段话:
- Select-String cmdlet 在输入字符串和文件中搜索文本和文本模式。你可以像使用 UNIX 中的 Grep 和 Windows 中的 Findstr 一样来使用它。可以键入“Select-String”或其别名“sls”。
- Select-String 类似于 UNIX 中的 Grep 命令和 Windows 中的 FindStr 命令。
文章目录
熟悉 Linux/Unix 的朋友们都知道,grep 命令有这样如下常见的参数:
本文将使用
Select-String
来对这些功能进行一一实现。
由于 grep -n
是列出每一个符合条件的行号,而 PowerShell 默认就会输出行数,这里不再提此。
递归搜索
对比 grep -r
使用 Get-ChildItem -Path 文件路径 -Recurse | select-string -pattern "模式"
例子:我在 E:\2笔记&&资料\test
有一个文件 FactoryPattern.txt
和若干目录:
用上述命令结果如下(因为我已经 cd 到此目录下了,故没指定 -Path)
输出有点乱,看不出文件层次,不知道有没有更美观的方法, 希望有人能够给出建议。下图是 grep 的,也有点乱:
在 https://antjanus.com/blog/web-development-tutorials/how-to-grep-in-powershell/ 找到了美观输出的方法。显示的有点不对…
PS E:\2笔记&&资料\test> Get-ChildItem -Recurse | Select-String -Pattern "干" | Select Filename, LineNumber, Line, Path | Format-Table
区分大小写
对比 grep -i
使用开关参数(SwitchParameter) -CaseSensitive
。
默认情况下,匹配项不区分大小写。
只打印出匹配行的数量
对比 grep -c
PS C:\>$f = select-string -path audit.log -pattern "logon failed"
PS C:\>$f.count
第二个命令使用对象数组的 Count 属性来显示找到的匹配项数
比如说,有4行有 logon failed
这个 pattern,输出就是 4。
捕获具有匹配项的行前后的指定行数
对比 grep -C N
-Context <Int32[]>
PS C:\>$f = select-string -path audit.log -pattern "logon failed" -context 2, 3
此命令将在 Audit.Log 文件中搜索短语“logon failed”。它使用 Context 参数来捕获匹配项的前 2 行和后 3 行。
搜索多个匹配项(贪婪模式)
使用开关参数 -AllMatches
在每个文本行中搜索多个匹配项。在没有此参数的情况下,Select-String
只会查找每个文本行中的第一个匹配项。
这个参数帮助文档是这样写的,但是其作用我也不太知道,因为 Select-String 默认好像也可以以搜全。
匹配多个模式
对比 grep -e 表达式
来自 https://cloud.tencent.com/developer/ask/41837
例如搜索C:\Logs that contain the words "VendorEnquiry"和“Failed”的所有文件
方法一
Get-ChildItem C:\Logs |
where { $_ | Select-String -Pattern 'VendorEnquiry' } |
where { $_ | Select-String -Pattern 'Failed' } |
...
方法二
改进方法一,可以用一个筛选器来简化这个过程来匹配多个模式,而不是手动编写每个Select-String调用。
filter MultiSelect-String( [string[]]$Patterns ) {
# Check the current item against all patterns.
foreach( $Pattern in $Patterns ) {
# If one of the patterns does not match, skip the item.
$matched = @($_ | Select-String -Pattern $Pattern)
if( -not $matched ) {
return
}
}
# If all patterns matched, pass the item through.
$_
}
Get-ChildItem C:\Logs | MultiSelect-String 'VendorEnquiry','Failed',...
方法三
如果要按任意顺序匹配这两个单词,使用:
Get-ChildItem C:\Logs| select-string -pattern '(VendorEnquiry.*Failed)|(Failed.*VendorEnquiry)'
反转
对比 grep -v
使用开关参数 -NotMatch
查找与指定的模式不匹配的文本。
不要求输出
对比 grep -q
使用开关参数 -Quiet
返回布尔值(true 或 false),而不是 MatchInfo 对象。如果找到该模式,则该值为“true”;否则为“false”。
从文件读取匹配模式 pattern
对比 grep -f
即 grep --file=filename
。其中 filename 指的是一个含有多行文本的文件名,而每行文本是一个匹配模式。
Get-Content .\doc.txt | Select-String -Pattern (Get-Content .\regex.txt)
其中 .\regex.txt 是那个每行都是一个匹配模式的文件,而 .\doc.txt 则是我们要搜索的文件。
参考 https://stackoverflow.com/questions/15199321/powershell-equivalent-to-grep-f
至于 grep
的 -w word
、 -l
和 -h
没见过实际例子,这里不提。
突然发现 PowerShell 下使用 grep 可以搜中文,而 cmd 下面的搜不了…
这就是说使用 PowerShell 既可以使用 Linux/Unix 命令带来的便捷还可以使用 PowerShell 提供的命令,就好像手上有了两把武器。
当然此文侧重在简单对比,Select-String 和 grep 的其他高级用法这里并没有涉及。