PowerShell Write-Output是默认的输出行为,问题是我们为什么需要它?

vxbzzdmp  于 2023-06-23  发布在  Shell
关注(0)|答案(2)|浏览(126)

正如这里所描述的,https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/write-output所有的Write-Output都是将输出发送到当前的输出设备,这是默认的。
看起来,显式使用Write-Output的唯一优点是能够提供参数NoEnumerate。对吗?
如果没有,那么使用写输出的其他情况是什么?

cgyqldqp

cgyqldqp1#

让我用一个使用Write-Output的理由(希望是详尽的)来补充Keith Langmead's answer

  • 有关PowerShell的 * 隐式 * 输出行为的讨论,请参阅this answer
    (有争议)可读性:Write-Output作为产生输出的意图的显式信号:
  • 基思的回答表明,使用Write-Output有助于可读性和可维护性,因为它表明了“显式”生成输出的意图。
  • zett42指出,这可能会使代码 * 更冗长 *,也会导致 * 性能损失 *,导致他更喜欢 * 隐式 * 输出,但用注解 * 装饰它以表明意图;例如$foo # output
  • 我同意:将语言隐式提供的内容显式化是多余的,并且可能给予没有经验的代码读者的误解,认为Write-Output是 * 必需的 *(例如,类似于您在cmd.exe和Bash中 * 实际上 * 需要echo; echo是PowerShell中Write-Output的 * 内置别名 *);对于有经验的读者来说,这样的呼叫相当于噪声。
  • 从某种意义上说,明确使用Write-Output表达了与语言核心特性之一的持续分歧,尽管其他语言的用户不熟悉,但可以“拥抱”,从而产生更简洁,无干扰的代码,也表现得更好。
    *输出数组(列表式集合) 作为一个整体 *,即作为单个对象,使用Write-Output -NoEnumerate**:
  • 正如您所注意到的,-NoEnumerate交换机可以用来实现这一点;例如:
# -> 'Array has 3 elements', i.e. $_ refers to the *entire array*
 #    created with (1..3), due to -NoEnumerate.
 Write-Output -NoEnumerate (1..3) | 
   ForEach-Object { "Array has $($_.Count) elements." }
  • 然而,有一个更简洁(尽管对初学者来说有点晦涩)和性能更好的替代方案:使用,unary 形式的数组构造函数运算符将数组 Package 在 *transient,单元素数组 * 中,当像往常一样在管道中枚举时,会导致 Package 的数组作为一个整体发送:
# -> 'Array has 3 elements', i.e. $_ refers to the *entire array*
 #    created with (1..3), due to wrapping (1..3) in a 
 #    transient, single-element wrapper array.
 , (1..3) | 
   ForEach-Object { "Array has $($_.Count) elements." }

*展平 * 数组(... | Write-Output):

  • 正如Santiago Squarzon所指出的,将多个数组通过管道传输到Write-Output会隐式地 * 展平 * 它们,即:返回一个包含输入数组所有元素的一维数组;例如:
# Create a jagged array (an array of arrays)
# -> @( @(1, 2, 3), @(4, 5) )
$arrayOfArrays = (1..3), (4..5)

# Flatten it by piping to Write-Output:
# -> @(1, 2, 3, 4, 5)
$arrayOfArrays | Write-Output

**使用common parameters,特别是-OutVariable-PipelineVariable

  • -OutVariable-ov)允许您将Write-Output的输出保存到所选的变量中,同时还可以通过管道发送输出。
  • -PipelineVariable-pv)将每个输出对象保存到所选的变量中,然后可以在后续管道段的 script block 参数中访问该变量。
  • 注意:由于这些是 common 参数,如果输出是由 * cmdlet * 或类似cmdlet的advanced函数和脚本生成的,则不需要Write-Output,因为您可以在此类命令中直接使用这些参数。但是,如果输出是由 * 简单 * 函数和脚本或 * 外部程序 * 生成的,则需要Write-Host来使用这些公共参数;例如(这些是人为的,但简单的例子):
# Stores the output from cmd /c dir /b /A:d in variable $dirOutput
 # but also sends it through the pipeline to Measure-Object
 Write-Output -OutVariable dirOutput (cmd /c dir /b /A:d) | Measure-Object

 # Stores each directory name output by cmd /c dir /b /A:d in 
 # variable $thisDir and previews (-WhatIf) a Rename-Item operation
 # that prepends "new_" to each directory name.
 Write-Output -PipelineVariable thisDir (cmd /c dir /b /A:d) |
   Rename-Item -NewName { "new_" + $thisDir } -WhatIf

**语法便利性 :创建(简单)字符串数组:

  • 假设字符串作为 command arguments 只在包含特殊字符(特别是 * 空格 *)时才需要引号,使用Write-Output提供了一种语法上更简单的数组字面量替代方案。
  • 此外,您可以在元素之间省略,,因为Write-Output允许 * 单独 * 指定参数。
  • 这种技术可能最好限制在交互式使用和“一次性”脚本中。
  • 比如说;注意,具有元字符的元素(例如,two and a half)将需要引用任何方式('two and a half'):
# Array literal (@(...) enclosure is optional)
@('one', 'two', 'three')

# Syntactically simpler Write-Output equivalent, using its 'echo' alias:
echo one two three
polhcujo

polhcujo2#

我认为主要的优点实际上是代码的可读性,因为它可以很容易地看到您正在向输出发送的内容。
例如,即使是像

$foo = "Current date is $(get-date)"

我认为扫描代码行更容易立即理解发生了什么,当你看到

Write-Output $foo

而不是仅仅看到

$foo

在自己的线路上。
也许值得注意的是,缩短形式似乎正在过时,或者不再以同样的方式推荐。例如,如果您使用VS Code编辑Powershell代码,您可能会注意到它显示了使用别名的警告,例如ft aliasing Format-Tableselect aliasing Select-Object等,其中列出的原因相同,这使得维护代码变得更加困难。

相关问题