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

huangapple go评论57阅读模式
英文:

Powershell Write-Output is a default output behaviour. The question is why do we need it at all?

问题

根据https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/write-output上的描述,Write-Output仅将输出发送到当前输出设备,这通常是默认设置。

似乎,显式使用Write-Output的唯一优势是能够提供参数-NoEnumerate。这正确吗?

如果不是,请问还有哪些情况可以使用Write-Output?

英文:

As described here
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/write-output
all Write-Output does is sends the output to the current output device, which is a default anyway.

It appears, that the only advantage of having explicitly used Write-Output is the ability to provide a parameter -NoEnumerate. Is that correct?

If not, then what are other cases for using Write-Output?

答案1

得分: 2

抱歉,这段内容是代码注释,无需翻译。

英文:

<!-- language-all: sh -->

Let me complement Keith Langmead's answer with a - hopefully exhaustive - list of reasons to use Write-Output:

  • For a discussion of PowerShell's implicit output behavior, see this answer.

(Debatable) readability: Write-Output as an explicit signal of the intent to produce output:

  • Keith's answer suggests that use of Write-Output helps readability and maintainability in that it signals the intent to produce output explicitly.

  • zett42 notes that this can make code more verbose and also incurs a performance penalty, causing him to prefer implicit output, but decorating it with a comment to signal the intent; e.g. $foo # output

  • I agree: Making explicit what the language implicitly provides is redundant, and may give rise to the misconception in inexperienced readers of the code that Write-Output is required (analogous to how you actually need echo in cmd.exe and Bash, for instance; as noted echo is a built-in alias of Write-Output in PowerShell); to the experienced reader, such calls amount to noise.

  • In a manner of speaking, explicit Write-Output use expresses an ongoing disagreement with one the language's core features, which - while unfamiliar to users of other languages - can be embraced, resulting in more concise, distraction-free code that also performs better.

Outputting arrays (list-like collections) as a whole, i.e. as a single object, with Write-Output -NoEnumerate:

  • As you note, the -NoEnumerate switch can be used to achieve that; e.g.:

     # -&gt; &#39;Array has 3 elements&#39;, i.e. $_ refers to the *entire array*
     #    created with (1..3), due to -NoEnumerate.
     Write-Output -NoEnumerate (1..3) | 
       ForEach-Object { &quot;Array has $($_.Count) elements.&quot; }
    
  • However, there is a more concise - albeit somewhat obscure to beginners - and better-performing alternative: use of the unary form of , the array constructor operator to wrap an array in a transient, single-element array, which, when enumerated in the pipeline as usual, results in the wrapped array being sent as a whole:

     # -&gt; &#39;Array has 3 elements&#39;, 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 { &quot;Array has $($_.Count) elements.&quot; }
    

Flattening arrays (... | Write-Output):

  • As Santiago Squarzon points out, piping multiple arrays to Write-Output implicitly flattens them, i.e. returns a single-dimensional array that contains all the elements of the input arrays; e.g.:

    # Create a jagged array (an array of arrays)
    # -&gt; @( @(1, 2, 3), @(4, 5) )
    $arrayOfArrays = (1..3), (4..5)
    
    # Flatten it by piping to Write-Output:
    # -&gt; @(1, 2, 3, 4, 5)
    $arrayOfArrays | Write-Output 
    

Use with common parameters, notably -OutVariable and -PipelineVariable:

  • -OutVariable (-ov) allows you to save Write-Output's output to a variable of choice while also sending the output through the pipeline.

  • -PipelineVariable (-pv) saves each output object to a variable of choice that can then be accessed in the script block arguments of subsequent pipeline segments.

  • Note: Given that these are common parameters, you won't need Write-Output if your output is produced by cmdlets or the cmdlet-like advanced functions and scripts, because you can use these parameters directly with such commands. However, you do need Write-Host in order to use these common parameters if the output is produced by simple functions and scripts or external programs; e.g. (these are contrived, but simple examples):

     # 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 &quot;new_&quot; to each directory name.
     Write-Output -PipelineVariable thisDir (cmd /c dir /b /A:d) |
       Rename-Item -NewName { &quot;new_&quot; + $thisDir } -WhatIf
    

Syntactic convenience: creation of arrays of (simple) strings:

  • Given that strings as command arguments only need quoting if they contain special characters, notably spaces, use of Write-Output offers a syntactically simpler alternative to array literals.

  • Additionally, you can then omit , between the elements, given that Write-Output allows specifying arguments individually.

  • This technique is probably best limited to interactive use and "throw-away" scripts.

  • For instance; note that elements with metacharacters (e.g. two and a half) would need quoting either way (&#39;two and a half&#39;):

    # Array literal (@(...) enclosure is optional)
    @(&#39;one&#39;, &#39;two&#39;, &#39;three&#39;)
    
    # Syntactically simpler Write-Output equivalent, using its &#39;echo&#39; alias:
    echo one two three
    

答案2

得分: 1

我认为主要优势实际上归结为代码的可读性,因为一目了然地看到你将某些内容发送到输出是非常容易的。

例如,即使是像

$foo = "当前日期是 $(get-date)"

我会认为在浏览代码行时,当你看到

Write-Output $foo

时,立即理解正在发生的事情要比仅仅看到

$foo

在单独的一行上容易得多。

也许值得注意的是,缩写形式似乎不再流行,或者不再以相同的方式被推荐。例如,如果你在VS Code中编辑PowerShell代码,你可能会注意到它显示关于别名的警告,例如 ft 别名为 Format-Tableselect 别名为 Select-Object 等,原因是这使得代码更难维护。

英文:

I think the main advantage really comes down to readability of your code, as it becomes easy at a glance to see that you're sending something to the output.

For instance, even with something as simple as

$foo = &quot;Current date is $(get-date)&quot;

I would argue that scanning through lines of code it's far easier to instantly understand what's happening when you see

Write-Output $foo

than if you just see

$foo

on a line of its own.

It's perhaps worth noting that shortened forms appear to be going out of popularity, or no longer being recommended in the same way. For instance if you edit Powershell code with VS Code you'll perhaps notice it showing warnings for the use of aliases, for instance ft aliasing Format-Table, select aliasing Select-Object etc, with the same listed reasoning that it makes it harder to maintain the code.

huangapple
  • 本文由 发表于 2023年5月22日 20:03:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/76305996.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定