什么Get-Content
真正输出,一个字符串或一个具有多个属性的对象?如果它是一个对象,哪个属性包含字符串,我可以修改该属性吗?该文件只有一行,所以我不必处理对象数组。
PS C:\Users\me> Get-Content input.txt 111 PS C:\Users\me> Get-Content input.txt | 选择对象 * PSPath : C:\Users\me\input.txt PSParentPath : C:\Users\me PSChildName : 输入 驱动器:C PSProvider : Microsoft.PowerShell.Core\FileSystem 读取计数:1 长度 : 3 PS C:\Users\me> (Get-Content input.txt).GetType() IsPublic IsSerial 名称 BaseType —————————————————— 真真字符串 System.Object
-replace
擦除除长度以外的所有额外属性:
PS C:\Users\me> (Get-Content input.txt) -replace 111, 222 | 选择对象 * 长度 ------ 3
Get-Content
输出.NET对象的数组[1][string]
,每个对象代表输入文件中的一行。
但是,Get-Content
还使用附加属性装饰这些字符串对象,这些属性提供有关字符串来源的有用元数据。
所有数据检索PowerShell 提供程序cmdlet - Get-ChildItem
, Get-Item
, Get-Content
, ... - 执行此操作;具体来说,他们用以下NoteProperty
成员装饰他们的输出对象:PSPath
, PSParentPath
, PSChildName
, PSDrive
, PSProvider
。
这种装饰由PowerShell的特定(大部分)成为可能不可见的辅助类型,[psobject]
,其中.NET对象被包裹,并且其可以存储附加的属性。
通常,经过修饰的 .NET 对象的行为与正常情况一样;例如,输出由 返回的字符串按Get-Content
原样打印它们,没有指示它们现在包含其他属性(从 PowerShell 的角度来看)。
但是,当涉及到序列化时,或者[pscustomobject]
使用Select-Object *
或其他使用反射 (属性枚举)的上下文制作对象的克隆时,这些属性确实很重要,并且会浮出水面,如您的问题所示。
ConvertTo-Json
例如,当您使用 进行序列化时,PowerShell 还会序列化其他属性,并且 - 有点人为地 - 将字符串的内容表示为伪属性value
- 请参阅此答案。
访问.psobject.BaseObject
装饰[string]
实例 - 仅[2] - 允许您根据需要绕过PowerShell 添加的属性,仅返回底层 .NET[string]
实例(基础对象)。
在NoteProperty
由提供者小命令如添加的成员Get-Content
是实例成员,即,它们是专用于一个给定的对象。(PowerShell 的ETS(扩展类型系统)还允许您在类型级别装饰对象)。
因此,当构造一个新的 [string]
实例,如通过使用-replace
操作者(或者,一般地,返回的任何字符串操作新的字符串),则新实例并不具有额外的特性
从字符串操作的角度来看,即使是修饰过的字符串也只是字符串;添加的属性在此上下文中无关紧要。这种模式通常适用:装饰对象总是可以像它的 .NET 基对象一样运行,并且在大多数情况下也是如此。
[1] 严格来说,Get-Content
就像任何 cmdlet 一样,流式传输其输出对象,即将它们一个一个地发送到管道。只有当您捕获此输出(例如通过分配给变量)时,才会根据需要构造一个数组( [object[]]
),假设输入文件包含两行或更多行- 否则,唯一一行被捕获为自身,而不是包裹在数组 -有关更多信息,请参阅此答案。
[2] 在 PowerShell 版本 3 及更高版本中,实例 ETS 成员不再与给定的 .NET 基础对象的[psobject]
包装器相关联,而是与基础对象本身相关联,使用所谓的复活表。[string]
出于技术原因,实例是唯一的例外,这就是为什么只有使用[string]
实例才能真正获得未修饰的对象.psobject.BaseObject
- 对于所有其他类型,访问基础对象实际上是无操作的,因为返回的对象仍将显示实例 ETS成员(也是)。
但是,.psobject.BaseObject
对于访问基础对象的成员(属性、方法)仍然很有用,以防这些成员被同名的 ETS 成员遮蔽(覆盖)。
Get-Content
不带开关的 cmdlet返回-Raw
一个字符串数组,其中包含文本文件的所有行,并按换行符分割。Get-Content
与开关一起使用-Raw
,将文件的内容作为单个字符串返回,包括换行符。
话虽如此,如果(如您的情况)文本文件仅包含一行,PowerShell 会自动“拆箱”返回的数组并返回单个字符串。
.NET 中的字符串是对象,具有属性和方法。尝试"abc" | Get-Member
看看还有什么关于 String 对象的信息。
如果这样做"abc" | Select-Object *
,输出将是
Run Code Online (Sandbox Code Playgroud)Length ------ 3
PowerShell 现在仅显示Length
字符串的属性。
Get-Content
然而,正如Ansgar Wiechers已经评论的那样,向结果(字符串)对象添加了额外的信息,所有这些都与文件本身有关。( PSPath, PSParentPath, PSChildName, PSDrive, PSProvider, ReadCount
)。这些额外的属性都被添加为NoteProperty
,如果您这样做,您可以看到它们被添加
(Get-Content input.txt) | Get-Member
Run Code Online (Sandbox Code Playgroud)
这会返回一个令人印象深刻的列表,但该对象仍然是System.String类型。
当您使用-replace
对该字符串执行操作时(Get-Content input.txt) -replace 111, 222
,结果将是New String 对象,该对象不再具有额外的与文件相关的属性。现在它只是一个字符串,因此与它最初的来源无关。
希望能解释一下