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

时间:2010-12-03 14:11:39

标签: powershell

我使用PowerShell发现了一种奇怪的行为。

单独引用对象的输出与在同一对象上调用的ToString()方法的输出不同。

中调用的方法或属性是什么
Write-Output "$a"

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

> 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                                      

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

PS C:\temp\testps> $q  = Get-ChildItem . "*.txt"

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

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                                      

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

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

这是第一个对象的输出。看起来整个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                                      

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

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

2 个答案:

答案 0 :(得分:5)

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

Write-Output $a | Out-Default

Out-Default在管道的末尾隐式执行,它是根据格式化数据进行格式化的cmdlet。

"$a"案例中,使用ToString()表示。

答案 1 :(得分: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
    

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

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

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

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

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