我使用Get-AppxPackage
在我的电脑上安装了所有的软件包,并试图在使用Select-String
之前和之后用N行查找其中的所有匹配项。
但是,select字符串只显示一行匹配项,也没有显示所有匹配项。只有当我通过管道从Get-AppxPackage
输出时才会发生这种情况,而不是当我将其写入文件然后执行cat <filename> | select-string ...
时。
正如您在下面的示例中看到的,使用pipe和cat
的两个结果。我对cat
的结果感兴趣,即关于该应用程序的详细信息。
那么我在这里做错了什么?为什么输出不同?
示例(每个人都应该有MS Edge,所以我将使用它作为示例(:
PS > Get-AppxPackage | Select-String -pattern 'edge' -context 3, 3 -allmatches
Microsoft.Windows.StartMenuExperienceHost_10.0.18362.329_neutral_neutral_cw5n1h2txyewy
Microsoft.Windows.Cortana_1.13.0.18362_neutral_neutral_cw5n1h2txyewy
Microsoft.AAD.BrokerPlugin_1000.18362.329.0_neutral_neutral_cw5n1h2txyewy
> Microsoft.MicrosoftEdge_44.18362.329.0_neutral__8wekyb3d8bbwe
Microsoft.Windows.CloudExperienceHost_10.0.18362.329_neutral_neutral_cw5n1h2txyewy
Microsoft.Windows.ContentDeliveryManager_10.0.18362.329_neutral_neutral_cw5n1h2txyewy
Windows.CBSPreview_10.0.18362.329_neutral_neutral_cw5n1h2txyewy
Microsoft.Windows.Apprep.ChxApp_1000.18362.329.0_neutral_neutral_cw5n1h2txyewy
Microsoft.Win32WebViewHost_10.0.18362.329_neutral_neutral_cw5n1h2txyewy
Microsoft.PPIProjection_10.0.18362.329_neutral_neutral_cw5n1h2txyewy
> Microsoft.MicrosoftEdgeDevToolsClient_1000.18362.329.0_neutral_neutral_8wekyb3d8bbwe
Microsoft.LockApp_10.0.18362.329_neutral__cw5n1h2txyewy
> Microsoft.EdgeDevtoolsPlugin_10.0.18362.329_neutral_neutral_cw5n1h2txyewy
Microsoft.ECApp_10.0.18362.329_neutral__8wekyb3d8bbwe
Microsoft.CredDialogHost_10.0.18362.329_neutral__cw5n1h2txyewy
Microsoft.BioEnrollment_10.0.18362.329_neutral__cw5n1h2txyewy
PS > cat .appx-packages.txt | select-string -pattern 'edge' -context 3, 3 -allmatches
SignatureKind : System
Status : Ok
> Name : Microsoft.MicrosoftEdge
Publisher : CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
Architecture : Neutral
ResourceId :
Version : 44.18362.329.0
> PackageFullName : Microsoft.MicrosoftEdge_44.18362.329.0_neutral__8wekyb3d8bbwe
> InstallLocation : C:WindowsSystemAppsMicrosoft.MicrosoftEdge_8wekyb3d8bbwe
IsFramework : False
> PackageFamilyName : Microsoft.MicrosoftEdge_8wekyb3d8bbwe
PublisherId : 8wekyb3d8bbwe
IsResourcePackage : False
IsBundle : False
SignatureKind : System
Status : Ok
> Name : Microsoft.MicrosoftEdgeDevToolsClient
Publisher : CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
Architecture : Neutral
ResourceId : neutral
Version : 1000.18362.329.0
> PackageFullName : Microsoft.MicrosoftEdgeDevToolsClient_1000.18362.329.0_neutral_neutral_8wekyb3d8bbwe
> InstallLocation : C:WindowsSystemAppsMicrosoft.MicrosoftEdgeDevToolsClient_8wekyb3d8bbwe
IsFramework : False
> PackageFamilyName : Microsoft.MicrosoftEdgeDevToolsClient_8wekyb3d8bbwe
PublisherId : 8wekyb3d8bbwe
IsResourcePackage : False
IsBundle : False
SignatureKind : System
Status : Ok
> Name : Microsoft.EdgeDevtoolsPlugin
Publisher : CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
Architecture : Neutral
ResourceId : neutral
Version : 10.0.18362.329
> PackageFullName : Microsoft.EdgeDevtoolsPlugin_10.0.18362.329_neutral_neutral_cw5n1h2txyewy
> InstallLocation : C:WindowsSystemAppsMicrosoft.EdgeDevtoolsPlugin_cw5n1h2txyewy
IsFramework : False
> PackageFamilyName : Microsoft.EdgeDevtoolsPlugin_cw5n1h2txyewy
PublisherId : cw5n1h2txyewy
IsResourcePackage : False
IsBundle : False
tl;dr
从PowerShell v7.3开始,要使Select-String
通过控制台(终端(中看到的相同富字符串表示搜索非字符串输入,必须首先将输入管道传输到oss
:
Get-AppxPackage | oss | Select-String -Pattern 'edge' -Context 3, 3
注:
正如GitHub第10726期中所讨论的,这个中间步骤应该是而不是。
事实上,当您将非字符串输入管道传输到外部程序时,例如
findstr.exe
,这已经没有必要了,因为PowerShell随后隐式使用富字符串表示,因为它必须将输入作为(有意义的(字符串发送[1]顺便说一句:
Select-String
可以方便地搜索文本行,使用oss
可以搜索对象的格式化字符串表示,而不必知道或关心它们的特定结构。但是,如果确实了解结构,则通过不同的cmdlet(如
Where-Object
和Select-Object
(使用OO技术会更健壮。例如,以下程序根据.Name
属性过滤包,然后只选择感兴趣的属性:# Note: Get-AppXPackage *edge* would obviate the need for Where-Object Get-AppXPackage | Where-Object Name -like *edge* | Select-Object Name, Version
背景信息:
Select-String
,当给定输入而不是字符串时,在查找给定模式之前,对每个输入对象使用简单的.ToString()
字符串化[2]。
在您的情况下,Get-AppXPackage
字符串输出的[Microsoft.Windows.Appx.PackageManager.Commands.AppxPackage]
实例将变为完整的包名称(例如,Microsoft.MicrosoftEdge_44.18362.387.0_neutral__8wekyb3d8bbwe
(,这解释了您的输出。
为了使Select-String
在中搜索对象-的显示字符串表示,因为它们将打印到控制台,并且它们将出现在使用>
/Out-File
保存的文件中(cat
是Out-File
在Windows上的内置别名(-令人惊讶的是,
使用Out-String -Stream
作为中间管道段;从PowerShell v5开始,如果内存可用,为了简洁起见,可以使用内置的包装函数oss
:
# oss is a built-in wrapper function for Out-String -Stream
Get-AppxPackage | oss | Select-String -Pattern 'edge' -Context 3, 3
Out-String
使用PowerShell的格式化系统生成输入对象的人性化显示表示,与默认控制台输出、Format-*
cmdlet和>
/Out-File
的方式相同。-Stream
导致输出行通过管道逐个发送,以便Select-String
可以匹配各个行。
考虑到该解决方案既不明显又繁琐,如果Select-String
直接支持这种行为会很好,理想情况下默认,但至少在通过开关参数选择加入的基础上-请参阅GitHub上的功能请求#10726-如果您同意,请在那里投票支持该提案。
[1]自v7.3起,仅PowerShell";说出文本";当与外部程序通信时,因此在向非字符串对象传递数据时,它必须创建非字符串对象的字符串表示:请参阅此答案。虽然默认为以显示此类对象的字符串表示形式是有意义的,但请注意,此表示形式不适用于编程处理;对于后者,最好显式输出结构化文本格式,例如通过ConvertTo-Json
输出JSON
[2]更准确地说,.psobject.ToString()
是按原样调用的,或者-如果对象的ToString
方法支持IFormatProvider
类型的参数-则为.psobject.ToString([cultureinfo]::InvariantCulture)
,以获得区域性不变表示-有关详细信息,请参阅此答案