我使用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
答案 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
开始:
dir
返回System.Array [System.IO.FileSystemInfo]。由于数组未被任何代码捕获,因此PowerShell使用其FileSystemInfo的默认格式来显示数组的内容。
同样的事情发生在上面,但是你执行迭代。您实际上是将自己的数组写回管道,重新构建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
希望这清楚地表明您的示例在功能上等同于您的第一个示例。
在这里,您将数组中的每个对象转换为字符串,方法是在返回结果数组之前将其放在引号中(告诉PowerShell调用$a.tostring()
)。所以这一次,你将一个字符串数组返回到管道。由于您没有捕获该数组,因此PowerShell会将其默认文本输出发送到控制台,如果是字符串,则只是字符串的文本。
这与案例1和2类似,因为PowerShell正在使用其FileSystemInfo对象的默认输出格式。
这与3相同,因为您再次返回一个字符串数组。唯一的区别是语义......你明确地调用ToString()
而不是隐含地将对象放在引号中。
有关默认格式的详细信息,请查看help about_format