什么构成了 Powershell 中 Select-String 方法的 "line"?
What constitutes a "line" for Select-String method in Powershell?
我希望 Select-String
考虑 \r\n
(回车-return + 换行符)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 仅 return 那些包含匹配项的字符串?
"abc`r`ndef"
是一个字符串,如果您在控制台中回显 (Write-Output
) 将导致:
PS C:\Users\gpunktschmitz> echo "abc`r`ndef"
abc
def
Select-String
将回显每个包含 "abc" 的字符串。由于 "abc" 是字符串的一部分,因此这个字符串将被 selected.
"abc", "def"
是两个字符串的列表。在此处使用 Select-String
将首先测试 "abc" 然后 "def" 如果模式匹配 "abc"。因为只有第一个匹配,所以它将被 selected。
使用以下将字符串拆分为列表,select 仅包含 "abc"
的元素
"abc`r`ndef".Split("`r`n") | Select-String -Pattern "abc"
Guenther Schmitz 先生基本上解释了 Select-String
的正确用法,但我想补充一些观点来支持他的回答。
我针对这个 Select-String
cmdlet 做了一些逆向工程工作。它在 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当做一个完整的字符串,并没有做任何分割。
我在 github 上没有找到这个 cmdlet 的实际源代码,可能这个实用程序部分还没有开源。但是我找到了这个Select-String
的unit test。
$testinputone = "hello","Hello","goodbye"
$testinputtwo = "hello","Hello"
他们用于单元测试的测试字符串实际上是字符串列表。这意味着他们甚至没有考虑您的用例,很可能它只是为了接受字符串集合的输入而设计的。
但是,如果我们看一下 Microsoft 关于 Select-String
的 official document,我们确实看到它在谈论 line 很多,而它无法识别字符串中的 line。我个人的猜测是 line 的概念只有在 cmdlet 接受文件作为输入时才有意义,在这种情况下文件就像一个字符串列表,列表中的每个项目代表一个单行.
希望它能让事情更清楚。
Select-String
对每个对象进行操作(按需字符串化[1])输入对象.
一个多行字符串如"abc`r`ndef"
是一个单输入对象。
- 相比之下,
"abc", "def"
是一个包含两个元素的字符串 array,作为 two 输入对象传递。
为了确保多行字符串的行被单独传递,将字符串拆分成一个行数组 使用 PowerShell 的 -split
运算符:"abc`r`ndef" -split "`r?`n"
- (
?
使 `r
可选,以便也正确处理 `n
-only(LF-only,Unix 风格)行尾。)
简而言之:
"abc`r`ndef" -split "`r?`n" | Select-String -Pattern "abc"
等效的,使用带有正则表达式 (regex) 转义序列的 PowerShell 字符串文字(-split
的 RHS 是一个正则表达式):
"abc`r`ndef" -split '\r?\n' | Select-String -Pattern "abc"
有点不幸的是,Select-String
文档讨论了对 行 文本进行操作,因为真正的操作单位是输入 对象 - 正如我们所见,它们本身可能包含多行。
据推测,这来自 典型 通过 Get-Content
cmdlet 提供输入对象的用例,它输出文本文件的行 一个接一个 .
请注意,Select-String
不会 return 直接 匹配字符串 ,而是将它们包装在 [Microsoft.PowerShell.Commands.MatchInfo]
对象中,其中包含有关比赛。
然而,即使在那里存在行隐喻,因为它是 .Line
属性 包含匹配的 string.
[1] 可选阅读:Select-String
如何将输入对象字符串化
如果输入对象还不是字符串,则会将其转换为字符串,但可能不是您预期的方式:
松散地说,在每个非字符串输入对象上调用.ToString()
方法[2]
,对于非字符串 not 与您使用 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
字符串化,正如所讨论的在 this GitHub feature request.
[2] 更准确地说,.psobject.ToString()
会按原样调用,或者 - 如果对象的 ToString
方法支持 IFormatProvider
类型的参数- 作为 .psobject.ToString([cultureinfo]::InvariantCulture)
以获得 文化不变 表示 - 请参阅 this answer 了解更多信息。
我希望 Select-String
考虑 \r\n
(回车-return + 换行符)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 仅 return 那些包含匹配项的字符串?
"abc`r`ndef"
是一个字符串,如果您在控制台中回显 (Write-Output
) 将导致:
PS C:\Users\gpunktschmitz> echo "abc`r`ndef"
abc
def
Select-String
将回显每个包含 "abc" 的字符串。由于 "abc" 是字符串的一部分,因此这个字符串将被 selected.
"abc", "def"
是两个字符串的列表。在此处使用 Select-String
将首先测试 "abc" 然后 "def" 如果模式匹配 "abc"。因为只有第一个匹配,所以它将被 selected。
使用以下将字符串拆分为列表,select 仅包含 "abc"
的元素"abc`r`ndef".Split("`r`n") | Select-String -Pattern "abc"
Guenther Schmitz 先生基本上解释了 Select-String
的正确用法,但我想补充一些观点来支持他的回答。
我针对这个
Select-String
cmdlet 做了一些逆向工程工作。它在 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当做一个完整的字符串,并没有做任何分割。
我在 github 上没有找到这个 cmdlet 的实际源代码,可能这个实用程序部分还没有开源。但是我找到了这个
Select-String
的unit test。$testinputone = "hello","Hello","goodbye" $testinputtwo = "hello","Hello"
他们用于单元测试的测试字符串实际上是字符串列表。这意味着他们甚至没有考虑您的用例,很可能它只是为了接受字符串集合的输入而设计的。
但是,如果我们看一下 Microsoft 关于
Select-String
的 official document,我们确实看到它在谈论 line 很多,而它无法识别字符串中的 line。我个人的猜测是 line 的概念只有在 cmdlet 接受文件作为输入时才有意义,在这种情况下文件就像一个字符串列表,列表中的每个项目代表一个单行.
希望它能让事情更清楚。
Select-String
对每个对象进行操作(按需字符串化[1])输入对象.一个多行字符串如
"abc`r`ndef"
是一个单输入对象。- 相比之下,
"abc", "def"
是一个包含两个元素的字符串 array,作为 two 输入对象传递。
- 相比之下,
为了确保多行字符串的行被单独传递,将字符串拆分成一个行数组 使用 PowerShell 的
-split
运算符:"abc`r`ndef" -split "`r?`n"
- (
?
使`r
可选,以便也正确处理`n
-only(LF-only,Unix 风格)行尾。)
- (
简而言之:
"abc`r`ndef" -split "`r?`n" | Select-String -Pattern "abc"
等效的,使用带有正则表达式 (regex) 转义序列的 PowerShell 字符串文字(-split
的 RHS 是一个正则表达式):
"abc`r`ndef" -split '\r?\n' | Select-String -Pattern "abc"
有点不幸的是,Select-String
文档讨论了对 行 文本进行操作,因为真正的操作单位是输入 对象 - 正如我们所见,它们本身可能包含多行。
据推测,这来自 典型 通过 Get-Content
cmdlet 提供输入对象的用例,它输出文本文件的行 一个接一个 .
请注意,Select-String
不会 return 直接 匹配字符串 ,而是将它们包装在 [Microsoft.PowerShell.Commands.MatchInfo]
对象中,其中包含有关比赛。
然而,即使在那里存在行隐喻,因为它是 .Line
属性 包含匹配的 string.
[1] 可选阅读:Select-String
如何将输入对象字符串化
如果输入对象还不是字符串,则会将其转换为字符串,但可能不是您预期的方式:
松散地说,在每个非字符串输入对象上调用.ToString()
方法[2]
,对于非字符串 not 与您使用 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
字符串化,正如所讨论的在 this GitHub feature request.
[2] 更准确地说,.psobject.ToString()
会按原样调用,或者 - 如果对象的 ToString
方法支持 IFormatProvider
类型的参数- 作为 .psobject.ToString([cultureinfo]::InvariantCulture)
以获得 文化不变 表示 - 请参阅 this answer 了解更多信息。