PowerShell 下的 grep —— Select-String 详解及二者对比

tags: []

使用 help Select-String -ShowWindow 命令我们可以很容易的得到一份中文的帮助文档,其中有这样两段话:

  1. Select-String cmdlet 在输入字符串和文件中搜索文本和文本模式。你可以像使用 UNIX 中的 Grep 和 Windows 中的 Findstr 一样来使用它。可以键入“Select-String”或其别名“sls”。
  2. Select-String 类似于 UNIX 中的 Grep 命令和 Windows 中的 FindStr 命令。

文章目录

    • tags: []
    • 递归搜索(对比 `grep -r`)
    • 区分大小写(对比 `grep -i` )
    • 只打印出匹配行的数量(对比 `grep -c` )
    • 捕获具有匹配项的行前后的指定行数(对比 `grep -C N` )
    • 搜索多个匹配项(贪婪模式)
    • 匹配多个模式(对比 `grep -e 表达式`)
      • 方法一
      • 方法二
      • 方法三
    • 反转(对比 `grep -v`)
    • 不要求输出(对比 `grep -q`)
    • 从文件读取匹配模式 pattern(对比 `grep -f` )

熟悉 Linux/Unix 的朋友们都知道,grep 命令有这样如下常见的参数:

PowerShell 下的 grep —— Select-String 详解及二者对比_第1张图片

本文将使用 Select-String 来对这些功能进行一一实现。

由于 grep -n 是列出每一个符合条件的行号,而 PowerShell 默认就会输出行数,这里不再提此。

递归搜索(对比 grep -r

使用 Get-ChildItem -Path 文件路径 -Recurse | select-string -pattern "模式"

例子:我在 E:\sourcecode\bin\test 有一个文件 FactoryPattern.txt 和若干目录:

E:\sourcecode\bin\test>tree /f
卷 文档 的文件夹 PATH 列表
卷序列号为 0008-09A4
E:.
│  FactoryPattern.txt
├─1
│  │  FactoryPattern1.txt
│  └─1.1
│          FactoryPattern1.1.txt
├─2
│      FactoryPattern2.txt
└─3
        FactoryPattern3.txt

用上述命令结果如下(因为我已经 cd 到此目录下了,故没指定 -Path)

PS E:\sourcecode\bin\test> Get-ChildItem -Recurse | Select-String -Pattern "干"

FactoryPattern.txt:9:mozzarella n. 意大利白色干酪
FactoryPattern.txt:11:parmesan n. 帕尔马干酪 adj. 巴马的(a hard, dry cheese used in grated form, especially on Italian
 dishes.)
FactoryPattern.txt:15:reggiano n. 干酪
1\FactoryPattern1.txt:9:mozzarella n. 意大利白色干酪
1\FactoryPattern1.txt:11:parmesan n. 帕尔马干酪 adj. 巴马的(a hard, dry cheese used in grated form, especially on Ital
ian dishes.)
1\FactoryPattern1.txt:15:reggiano n. 干酪
1\1.1\FactoryPattern1.1.txt:9:mozzarella n. 意大利白色干酪
1\1.1\FactoryPattern1.1.txt:11:parmesan n. 帕尔马干酪 adj. 巴马的(a hard, dry cheese used in grated form, especially o
n Italian dishes.)
1\1.1\FactoryPattern1.1.txt:15:reggiano n. 干酪
2\FactoryPattern2.txt:9:mozzarella n. 意大利白色干酪
2\FactoryPattern2.txt:11:parmesan n. 帕尔马干酪 adj. 巴马的(a hard, dry cheese used in grated form, especially on Ital
ian dishes.)
2\FactoryPattern2.txt:15:reggiano n. 干酪
3\FactoryPattern3.txt:9:mozzarella n. 意大利白色干酪
3\FactoryPattern3.txt:11:parmesan n. 帕尔马干酪 adj. 巴马的(a hard, dry cheese used in grated form, especially on Ital
ian dishes.)
3\FactoryPattern3.txt:15:reggiano n. 干酪

输出有点乱,看不出文件层次,不知道有没有更美观的方法, 希望有人能够给出建议。下图是 grep 的,也有点乱:

PS E:\sourcecode\bin\test> grep -nr "干"
1/1.1/FactoryPattern1.1.txt:9:mozzarella n. 意大利白色干酪
1/1.1/FactoryPattern1.1.txt:11:parmesan n. 帕尔马干酪 adj. 巴马的(a hard, dry cheese used in grated form, especially on
 Italian dishes.)
1/1.1/FactoryPattern1.1.txt:15:reggiano n. 干酪
1/FactoryPattern1.txt:9:mozzarella n. 意大利白色干酪
1/FactoryPattern1.txt:11:parmesan n. 帕尔马干酪 adj. 巴马的(a hard, dry cheese used in grated form, especially on Itali
an dishes.)
1/FactoryPattern1.txt:15:reggiano n. 干酪
2/FactoryPattern2.txt:9:mozzarella n. 意大利白色干酪
2/FactoryPattern2.txt:11:parmesan n. 帕尔马干酪 adj. 巴马的(a hard, dry cheese used in grated form, especially on Itali
an dishes.)
2/FactoryPattern2.txt:15:reggiano n. 干酪
3/FactoryPattern3.txt:9:mozzarella n. 意大利白色干酪
3/FactoryPattern3.txt:11:parmesan n. 帕尔马干酪 adj. 巴马的(a hard, dry cheese used in grated form, especially on Itali
an dishes.)
3/FactoryPattern3.txt:15:reggiano n. 干酪
FactoryPattern.txt:9:mozzarella n. 意大利白色干酪
FactoryPattern.txt:11:parmesan n. 帕尔马干酪 adj. 巴马的(a hard, dry cheese used in grated form, especially on Italian
dishes.)
FactoryPattern.txt:15:reggiano n. 干酪

在 https://antjanus.com/blog/web-development-tutorials/how-to-grep-in-powershell/ 找到了美观输出的方法。显示的有点不对…

Get-ChildItem -Recurse | Select-String -Pattern "干" | Select Filename, LineNumber, Line, Path | Format-Table
PS E:\sourcecode\bin\test> Get-ChildItem -Recurse | Select-String -Pattern "干" | Select Filename, LineNumber, Line, Pat
h | Format-Table

Filename                 LineNumber Line                          Path
--------                 ---------- ----                          ----
FactoryPattern.txt                9 mozzarella n. 意大利白色干酪  E:\sourcecode\bin\test\Fac...
FactoryPattern.txt               11 parmesan n. 帕尔马干酪 adj... E:\sourcecode\bin\test\Fac...
FactoryPattern.txt               15 reggiano n. 干酪              E:\sourcecode\bin\test\Fac...
FactoryPattern1.txt               9 mozzarella n. 意大利白色干酪  E:\sourcecode\bin\test\1\F...
FactoryPattern1.txt              11 parmesan n. 帕尔马干酪 adj... E:\sourcecode\bin\test\1\F...
FactoryPattern1.txt              15 reggiano n. 干酪              E:\sourcecode\bin\test\1\F...
FactoryPattern1.1.txt             9 mozzarella n. 意大利白色干酪  E:\sourcecode\bin\test\1\1...
FactoryPattern1.1.txt            11 parmesan n. 帕尔马干酪 adj... E:\sourcecode\bin\test\1\1...
FactoryPattern1.1.txt            15 reggiano n. 干酪              E:\sourcecode\bin\test\1\1...
FactoryPattern2.txt               9 mozzarella n. 意大利白色干酪  E:\sourcecode\bin\test\2\F...
FactoryPattern2.txt              11 parmesan n. 帕尔马干酪 adj... E:\sourcecode\bin\test\2\F...
FactoryPattern2.txt              15 reggiano n. 干酪              E:\sourcecode\bin\test\2\F...
FactoryPattern3.txt               9 mozzarella n. 意大利白色干酪  E:\sourcecode\bin\test\3\F...
FactoryPattern3.txt              11 parmesan n. 帕尔马干酪 adj... E:\sourcecode\bin\test\3\F...
FactoryPattern3.txt              15 reggiano n. 干酪              E:\sourcecode\bin\test\3\F...

我们注意到 Path 这一栏下面的部分内容被省略号替换掉了。怎么让它显示全呢?我们需要两个步骤

  1. 首先让 Format-table 不再截断内容,这个可以通过开关参数 -Autosize 完成。但是由于 PowerShell 窗口有个宽度限制使我们不能看全,内容依然被截断了。
  2. 所以我们最好导出到文件中,使用 Out-File -Width len 来指定导出文件的宽度,这个 len 宽度最好大于我们输出内容的最大宽度。

一个例子

$results | Format-Table -AutoSize | Out-File -Width 512 C:\log.txt -Append

参考 How do I use Format-Table without truncation of values?

区分大小写(对比 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

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 -fgrep --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 下的 grep —— Select-String 详解及二者对比_第2张图片

PowerShell 下的 grep —— Select-String 详解及二者对比_第3张图片

这就是说使用 PowerShell 既可以使用 Linux/Unix 命令带来的便捷还可以使用 PowerShell 提供的命令,就好像手上有了两把武器。

当然此文侧重在简单对比,Select-String 和 grep 的其他高级用法这里并没有涉及。

你可能感兴趣的:(#,PowerShell读书笔记)