Powershell中的Write-Output对对象调用的默认方法是什么?

ser*_*iom 4 powershell

我发现使用PowerShell有一种奇怪的行为.

仅引用对象的输出与在同一对象上调用的ToString()方法的输出不同.

调用的方法或属性是什么

Write-Output "$a"
Run Code Online (Sandbox Code Playgroud)

这是我正在运行该示例的目录

> PS C:\temp\testps> DIR


    Directory: C:\temp\testps


Mode                LastWriteTime     Length Name                                       
----                -------------     ------ ----                                       
-a---        03/12/2010     11.21          8 1.txt                                      
-a---        03/12/2010     11.21          8 2.txt                                      
-a---        03/12/2010     11.21          8 3.txt                                      
Run Code Online (Sandbox Code Playgroud)

在这里,我将文件集合分配给$ q对象

PS C:\temp\testps> $q  = Get-ChildItem . "*.txt"
Run Code Online (Sandbox Code Playgroud)

现在我想打印文件名,但是我收到了意外的输出

PS C:\temp\testps> foreach ($a in $q) {Write-Output $a}


    Directory: C:\temp\testps


Mode                LastWriteTime     Length Name                                       
----                -------------     ------ ----                                       
-a---        03/12/2010     11.21          8 1.txt                                      
-a---        03/12/2010     11.21          8 2.txt                                      
-a---        03/12/2010     11.21          8 3.txt                                      
Run Code Online (Sandbox Code Playgroud)

在对象名称周围加上引号会显示正确的行为

PS C:\temp\testps> foreach ($a in $q) {Write-Output "$a"}
1.txt
2.txt
3.txt
Run Code Online (Sandbox Code Playgroud)

这是第一个对象的输出.看起来整个DIR命令输出直到第一个文件名.非解析.

PS C:\temp\testps> foreach ($a in $q) {Write-Output $a;break}


    Directory: C:\temp\testps


Mode                LastWriteTime     Length Name                                       
----                -------------     ------ ----                                       
-a---        03/12/2010     11.21          8 1.txt                                      
Run Code Online (Sandbox Code Playgroud)

ToString()方法的行为类似于引用的对象.

PS C:\temp\testps> foreach ($a in $q) {Write-Output $a.ToString()}
1.txt
2.txt
3.txt
Run Code Online (Sandbox Code Playgroud)

Kei*_*ill 5

在第一种情况下Write-Output $a,对象(System.IO.FileInfo)由PowerShell格式化引擎根据存储的格式数据进行格式化$pshome\FileSystem.format.ps1xml.也就是说,真正执行的是:

Write-Output $a | Out-Default
Run Code Online (Sandbox Code Playgroud)

Out-Default在管道的末尾隐式执行,它是基于格式化数据执行格式化的cmdlet.

在这种"$a"情况下,使用ToString()表示.


Rob*_*cio 5

Write-Output实际上只是将您提供给它的对象发送到pipleine中的下一个命令的一种显式方式.由于您不捕获输出,PowerShell使用对象的默认格式.这是因为Write-Output实际上并没有向stdout发送字符串,而是将对象返回到管道.第一种情况中的对象是FileSystemInfo对象的数组.

当您在PowerShell中返回数组而不捕获输出时,PowerShell会尝试迭代数组并使用其默认格式规范将每个对象显示为stdout上的文本.

因此,按照您提供的示例顺序,从dir:

  1. dir返回System.Array [System.IO.FileSystemInfo].由于数组未被任何代码捕获,因此PowerShell使用其FileSystemInfo的默认格式来显示数组的内容.

  2. 同样的事情发生在上面,但是你执行迭代.实际上,您正在将自己的数组写回管道,重新构建get-childitem首先返回的相同对象.因为,再一次,没有代码捕获输出数组对象,PowerShell就像第一种情况一样显示它.就像你写的那样:

    PS C:\temp\testps> $q  = Get-ChildItem . "*.txt"
    PS C:\temp\testps> $children = foreach ($a in $q) {Write-Output $a}
    PS C:\temp\testps> $children
    
    Run Code Online (Sandbox Code Playgroud)

    希望这清楚地表明您的示例在功能上等同于您的第一个示例.

  3. 在这里,您将$a.tostring()在返回结果数组之前将数组中的每个对象转换为引号(告诉PowerShell调用)将其转换为字符串.所以这一次,你将一个字符串数组返回到管道.由于您没有捕获该数组,因此PowerShell会将其默认文本输出发送到控制台,如果是字符串,则只是字符串的文本.

  4. 这与情况1和2类似,因为PowerShell正在使用其FileSystemInfo对象的默认输出格式.

  5. 这与3相同,因为您再次返回一个字符串数组.唯一的区别是语义...... ToString()当你将对象放在引号中时,你是明确地而不是隐式地调用.

有关默认格式的详细信息,请查看 help about_format