PowerShell:write-output只写一个对象

时间:2016-10-26 08:38:07

标签: powershell

我正在学习PowerShell和我阅读的大量文章强烈反对使用write-host告诉我这是“不好的做法”,而且几乎总是,输出可以用另一种方式显示。

所以,我正在接受建议并尽量避免使用write-host。我发现的一个建议是使用写输出。据我所知,这将所有内容放在一个管道中,输出在脚本的末尾执行(?)。

但是,输出我想要的东西时遇到了问题。此示例演示了此问题:

$properties = @{'OSBuild'="910ef01.2.8779";
                'OSVersion'="CustomOS 3";
                'BIOSSerial'="A5FT-XT2H-5A4B-X9NM"}
$object = New-Object –TypeName PSObject –Prop $properties
Write-output $object

$properties = @{'Site'="SQL site";
                'Server'="SQL Server";
                'Database'="SQL Database"}
$object = New-Object –TypeName PSObject –Prop $properties
Write-Output $object

这样我得到了显示OS数据的第一个对象的良好输出,但是从不显示包含SQL数据的第二个对象。我已经尝试重命名变量名称和一些其他不同的东西,但没有运气。

在解决此问题时,我发现了类似的问题,建议只用write-host替换write-output。这让我很困惑。为什么有些人强烈反对写主持人,而其他人鼓励呢?

我究竟如何以时尚的方式输出这两个对象?我不完全理解写输出的管道机制。

3 个答案:

答案 0 :(得分:3)

  • 只是为了澄清:问题只是显示问题

    • 输出到控制台时,如果第一个对象是表格式(如果应用Format-Table,则会发生在您的情况下隐式),显示列基于第一个对象的属性锁定在中。
      由于您的第二个输出对象与第一个没有属性,因此它对表格显示没有任何贡献,因此实际上是不可见的。
    • 相比之下,如果您以编程方式处理脚本的输出 - 将其分配给变量或通过管道将其输出发送到另一个命令 - 两个对象都将在那里。
  • 显示问题的最简单的解决方案显式格式化显示每个输入对象单独 - 见下文。

对于脚本中的给定单个对象,您可以强制使用Out-Host 强制格式化显示(到主机)输出:

$object | Out-Host # same as: Write-Output $object | Out-Host

但请注意,此直接且始终只向控制台输出 ,然后该对象不属于脚本数据输出的一部分(写入成功输出流的对象,索引为1的流)。
换句话说:如果您尝试将脚本的输出分配给变量或将其输出发送到管道中的另一个命令,那么该对象就不会存在。

请参阅下文,了解Out-Host优于Write-Host的原因,以及为什么在大多数情况下避免Write-Host为何更好。

将ad hoc技术作为一个整体应用于给定的脚本输出,以确保您看到所有输出对象,请使用:< / p>

./some-script.ps1 | % { $_ | Out-String }  # % is the built-in alias of ForEach-Object

请注意,您也可以使用Out-Host,但使用Out-String的优势在于,如果需要,它仍然允许您捕获文件中的for-display表示。

这是一个简单的帮助函数(过滤器),可以放在$PROFILE中:

# Once defined, you can use: ./some-script.ps1 | Format-Each
Filter Format-Each { $_ | Out-String }

PetSerAl's建议 - ./some-script.ps1 | Format-List - 原则上也有效,但它会将输出从通常的样式输出切换到列表 -style输出,每个属性都在自己的行中列出,这可能是不受欢迎的 但是,相反,Format-Each,如果输出对象(隐式)为表格格式,则为每个对象打印标题

为什么Write-Output没有帮助:

Write-Output没有帮助,因为无论如何它都会写入默认输出对象的位置:前面提到的成功输出流,其中 data 应该去。

如果输出流的对象没有被重定向或以某种形式捕获,则默认情况下会将它们发送到主机(通常是控制台),其中自动格式化适用。

此外,使用Write-Output很少必要,因为只是没有捕获或重定向命令或表达式隐式地写入成功之流;另一种表达方式:
Write-Output 暗示

因此,以下两个陈述是等价的:

Write-Output $object  # write $object to the success output stream
$object               # same; *implicitly* writes $object to the success output stream

为什么使用Write-Host是不明智的,无论是在这里还是经常:

假设您确实知道一般使用Write-Host的含义 - 请参阅下文 - 您可以将其用于手头的问题,但 Write-Host应用简单.ToString()格式化为其输入为您提供默认情况下PowerShell应用的漂亮的多行格式。
因此,上面使用了Out-Host(和Out-String),因为他们应用相同的友好格式。

对比以下两个语句,它们打印一个哈希表([hashtable])文字:

# (Optional) use of Write-Output: The friendly, multi-line default formatting is used.
# ... | Out-Host and ... | Out-String would print the same.
PS> Write-Output @{ foo = 1; bar = 'baz' }

Name                           Value
----                           -----
bar                            baz
foo                            1

# Write-Host: The hashtable's *entries* are *individually* stringified
#             and the result prints straight to the console.
PS> Write-Host @{ foo = 1; bar = 'baz' }

System.Collections.DictionaryEntry System.Collections.DictionaryEntry    

Write-Host在这里做了两件事,导致几乎无用的输出:

  • [hashtable]个实例的条目枚举,每个条目都是单独字符串化的。

  • 哈希表条目(键值对)的.ToString()字符串化为System.Collections.DictionaryEntry,即只是实例的类型名称

一般中避免Write-Host 的主要原因是:

  • 它直接输出到主机(控制台)而不是PowerShell的成功输出流。

    • 作为初学者,您可能会错误地认为Write-Host用于撰写结果(数据),但它不是。
  • 绕过PowerShell的流系统,Write-Host输出无法重定向 - 也就是说,它既不能被压制也不能 捕获(在文件或变量中)。

    • 也就是说,从PowerShell v5.0开始, 现在可以通过新引入的信息流(编号6重定向其输出;例如,{ {1}});但是,该流更适合与新的./some-script.ps1 6>write-host-output.txt cmdlet一起使用 相比之下,Write-Information输出仍然无法重定向。

只留下Out-Host 的以下合法用途:

  • 创建最终用户提示和彩色仅供显示的表示

    • 您的脚本可能有交互式提示,要求用户提供信息;使用Write-Host - 可选择通过Write-Host-ForegroundColor参数着色 - 是合适的,因为提示字符串不应成为脚本输出的一部分,用户也提供输入通过主机(通常通过-BackgroundColor)。

    • 同样,您可以使用带有选择性着色的Read-Host来明确创建更友好的仅供显示表示。

  • 快速原型设计:如果您想要一种快速而简单的方法将状态/诊断信息直接写入控制台而不会干扰脚本的数据< / em>输出。

答案 1 :(得分:2)

一般来说,期望脚本/函数返回单个&#34;类型&#34;对象,通常有很多实例。例如,Get-Process返回一组进程,但它们都具有相同的字段。正如您从教程等中看到的那样,您可以沿着管道传递Get-Process的输出,并使用后续cmdlet处理数据。

在您的情况下,您将返回两种不同类型的对象(即具有两组不同的属性)。 PS会输出您发现的第一个对象,但不会输出第二个对象(它与第一个对象不匹配)。如果您要向第一个对象添加与第二个对象相匹配的额外属性,那么您将看到两个对象。

Write-Host并不关心这类事情。反对使用它的推迟主要是与(1)它是一种懒惰的方式来提供有关脚本进度的反馈,即使用Write-VerboseWrite-Debug而不是(2)当它不完美时来自管道等传递对象

  

关于第(2)点的澄清,在对这个答案的评论中有用地提出:

     

Write-Host不仅对管道不完美/   重定向/输出捕获,你根本无法使用它   PSv4及更早版本,在PSv5 +中你必须笨拙地使用6>;也,   Write-Host与经常生成的.ToString()字符串串联   无益的陈述

如果您的脚本真的只是打算将数据打印到控制台,那么请继续Write-Host

或者,您可以从脚本或函数返回多个对象。使用returnWrite-Output,只返回以逗号分隔的对象对象。例如:

试验WriteOutput.ps1

$object1 = [PSCustomObject]@{
  OSBuild = "910ef01.2.8779"
  OSVersion = "CustomOS 3"
  BIOSSerial = "A5FT-XT2H-5A4B-X9NM"
}

$object2 = [PSCustomObject]@{
  Site = "SQL site"
  Server= "SQL Server"
  Database="SQL Database"
}

Write-Output $object1,$object2

运行脚本,将输出分配为两个变量:

$a,$b = .\Test-WriteOutput.ps1

您会看到 $ a $ object1 $ b $ object2

答案 2 :(得分:0)

使用write-host,write-output用于管道(默认情况下在控制台上清除后)