7

我希望Select-String考虑\r\n(回车+换行)Powershell中一行的结尾。

但是,如下所示,abc匹配整个输入:

PS C:\Tools\hashcat> "abc`r`ndef" | Select-String -Pattern "abc"

abc
def

如果我将字符串分成两部分,则Select-String表现如我所料:

PS C:\Tools\hashcat> "abc", "def" | Select-String -Pattern "abc"

abc

我怎样才能给出Select-String一个以 结尾的字符串\r\n,然后让这个 cmdlet 只返回那些包含匹配项的字符串?

4

3 回答 3

7
  • Select-String对每个(按需字符串化[1]输入对象进行操作。

  • 字符串例如"abc`r`ndef"单个输入对象。

    • 相比之下,"abc", "def"是一个包含两个元素的字符串数组,作为两个输入对象传递。
  • 要确保单独传递多行字符串的,请使用 PowerShell 的运算符将字符串拆分为行数组-split"abc`r`ndef" -split "`r?`n"

    • (这?使得`r可选,以便也正确处理`n-only(LF-only,Unix-style)行尾。)

简而言之:

"abc`r`ndef" -split "`r?`n" | Select-String -Pattern "abc"

等效的,使用带有正则表达式 (regex) 转义序列的 PowerShell 字符串文字(RHS-split是一个正则表达式):

"abc`r`ndef" -split '\r?\n' | Select-String -Pattern "abc"

有点不幸的是,Select-String文档谈到对文本进行操作,因为真正的操作单元是输入对象——正如我们所见,输入对象本身可能包含多行。
据推测,这来自通过 cmdlet 提供输入对象的典型用例,该Get-Contentcmdlet 会逐行输出文本文件的

请注意,Select-String它不会直接返回匹配的字符串,而是将它们包装在[Microsoft.PowerShell.Commands.MatchInfo]包含有关匹配的有用元数据的对象中。然而,即使存在线隐喻,因为它是.Line包含匹配字符串的属性。


[1] 可选读物:如何Select-String对输入对象进行字符串化

如果输入对象还不是字符串,则将其转换为字符串,尽管可能不是您所期望的方式:

粗略地说,.ToString()在每个非字符串输入对象[2]上调用该方法 ,对于非字符串,这使用 PowerShell 的默认输出格式获得的表示不同(后者是您在将对象打印到例如,控制台或使用Out-File);相比之下,它在双引号字符串中使用字符串插值获得的表示相同(当您在 中嵌入变量引用或命令时"...",例如,"$HOME""$(Get-Date)")。

通常,.ToString()只产生对象类型的名称,而不包含任何特定于实例的信息;例如,$PSVersionTable字符串化为System.Management.Automation.PSVersionHashTable.

# Matches NOTHING, because Select-String sees
# 'System.Management.Automation.PSVersionHashTable' as its input.
$PSVersionTable | Select-String PSVersion 

如果您确实想逐行搜索默认输出格式,请使用以下成语:

... | Out-String -Stream | Select-String ...

但是,请注意,对于非字符串输入,后续处理通过使用条件查询属性Where-Object来过滤输入更加健壮和可取。

也就是说,有充分的理由Select-String需要隐式应用Out-String -Stream字符串化,如本 GitHub 功能请求中所述。


[2] 更准确地说,.psobject.ToString()按原样调用,或者 - 如果对象的ToString方法支持IFormatProvider-typed 参数 -.psobject.ToString([cultureinfo]::InvariantCulture)以获得文化不变的表示 - 请参阅此答案以获取更多信息。

于 2018-04-22T23:10:42.297 回答
2

基本上,Guenther Schmitz 先生解释了 的正确用法Select-String,但我只想添加一些要点来支持他的回答。

  1. 我针对这个Select-Stringcmdlet 做了一些逆向工程工作。它位于 Microsoft.PowerShell.Utility.dll 中。一些相关的代码片段如下,注意这些是来自逆向工程的代码供参考,而不是实际的源代码。

    string text = inputObject.BaseObject as string;
    ...
    matchInfo = (inputObject.BaseObject as MatchInfo);
    object operand = ((object)matchInfo) ?? ((object)inputObject);
    flag2 = doMatch(operand, out matchInfo2, out text);
    

    我们可以发现它只是将 inputObject 视为一个完整的字符串,它没有进行任何拆分。

  2. 我在 github 上没有找到这个 cmdlet 的实际源代码,可能这个实用程序部分还没有开源。但我找到了这个的单元测试Select-String

    $testinputone = "hello","Hello","goodbye"
    $testinputtwo = "hello","Hello"
    

    他们用于单元测试的测试字符串实际上是字符串列表。这意味着他们甚至没有考虑您的用例,而且很可能它只是为了接受字符串集合的输入而设计的。

  3. 但是,如果我们查看Microsoft的官方文档Select-String,我们确实看到它谈论了很多,而它无法识别字符串中的。我个人的猜测是的概念只有在 cmdlet 接受文件作为输入时才有意义,如果文件就像一个字符串列表,列表中的每个项目代表一行。

希望它能让事情变得更清楚。

于 2018-04-22T14:59:52.057 回答
2
"abc`r`ndef"

是一个字符串,如果您Write-Output在控制台中回显 ( ) 将导致:

PS C:\Users\gpunktschmitz> echo "abc`r`ndef"
abc
def

Select-String回显每个包含“abc”的字符串。由于“abc”是字符串的一部分,因此将选择该字符串。

"abc", "def"

是两个字符串的列表。如果模式匹配“abc”,则使用Select-String此处将首先测试“abc”,然后测试“def”。因为只有第一个匹配,它才会被选中。

使用以下将字符串拆分为列表并仅选择包含“abc”的元素

"abc`r`ndef".Split("`r`n") | Select-String -Pattern "abc"
于 2018-04-22T12:42:51.377 回答