我希望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仅返回包含匹配项的字符串?
答案 0 :(得分:3)
Select-String
对每个(按字母顺序排列的 [1] )输入对象进行操作。
多行字符串(例如"abc`r`ndef"
)是单个输入对象。
"abc", "def"
是一个带有两个元素的字符串 array ,作为两个输入对象传递。要确保多行字符串的行分别传递,请将字符串拆分为行数使用PowerShell的-split
运算符:"abc`r`ndef" -split "`r?`n"
?
使`r
成为可选项,以便正确处理`n
- 仅限(仅限LF,Unix风格)行结尾。)简而言之:
"abc`r`ndef" -split "`r?`n" | Select-String -Pattern "abc"
等效,使用带有正则表达式(正则表达式)转义序列的PowerShell字符串文字(-split
的RHS是正则表达式):
"abc`r`ndef" -split '\r?\n' | Select-String -Pattern "abc"
有些不幸的是Select-String
文档谈到了对文本的行进行操作,因为真正的操作单元是输入对象 - 这可能是正如我们所见,它们本身包含多条线
据推测,这来自于通过Get-Content
cmdlet提供输入对象的典型用例,它逐个输出文本文件的行 。
请注意,Select-String
不会直接返回匹配字符串 ,而是将它们包含在[Microsoft.PowerShell.Commands.MatchInfo]
个对象中,这些对象包含有关匹配的有用元数据。
即使存在行隐喻,因为.Line
属性包含匹配的字符串。
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
条件的输入。
[2]更准确地说,.psobject.ToString()
被调用,或者是 - 如果对象的ToString
方法支持IFormatProvider
- 类型的参数 - 作为{{ 1}}以便获得文化不变的表示 - 请参阅我的this answer作为背景。
答案 1 :(得分:2)
"abc`r`ndef"
是一个字符串,如果你在控制台中回显(Write-Output
)将导致:
PS C:\Users\gpunktschmitz> echo "abc`r`ndef"
abc
def
Select-String
将回显出“abc”所属的每个字符串。由于“abc”是字符串的一部分,因此将选择此字符串。
"abc", "def"
是两个字符串的列表。在这里使用Select-String
将首先测试“abc”,然后如果模式匹配“abc”则测试“def”。由于只有第一个匹配,它才会被选中。
使用以下内容将字符串拆分为列表,并仅选择包含“abc”
的元素"abc`r`ndef".Split("`r`n") | Select-String -Pattern "abc"
答案 2 :(得分:1)
基本上,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
的{{3}}。
$testinputone = "hello","Hello","goodbye"
$testinputtwo = "hello","Hello"
他们用于单元测试的测试字符串实际上是字符串列表。这意味着他们甚至没有考虑你的用例,很可能只是为了接受字符串集的输入。
但是,如果我们看一下微软的unit test关于Select-String
我们确实看到它谈论行很多而它无法识别字符串在一个字符串中。我的个人猜测是行的概念仅在cmdlet接受文件作为输入时才有意义,如果文件类似于字符串列表,则列表中的每个项目代表一行。
希望它能让事情更清楚。