英文:
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 needecho
incmd.exe
and Bash, for instance; as notedecho
is a built-in alias ofWrite-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.:# -> '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." }
-
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:# -> '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." }
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) # -> @( @(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
Use with common parameters, notably -OutVariable
and -PipelineVariable
:
-
-OutVariable
(-ov
) allows you to saveWrite-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 needWrite-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 "new_" to each directory name. Write-Output -PipelineVariable thisDir (cmd /c dir /b /A:d) | Rename-Item -NewName { "new_" + $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 thatWrite-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 ('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
答案2
得分: 1
我认为主要优势实际上归结为代码的可读性,因为一目了然地看到你将某些内容发送到输出是非常容易的。
例如,即使是像
$foo = "当前日期是 $(get-date)"
我会认为在浏览代码行时,当你看到
Write-Output $foo
时,立即理解正在发生的事情要比仅仅看到
$foo
在单独的一行上容易得多。
也许值得注意的是,缩写形式似乎不再流行,或者不再以相同的方式被推荐。例如,如果你在VS Code中编辑PowerShell代码,你可能会注意到它显示关于别名的警告,例如 ft
别名为 Format-Table
,select
别名为 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 = "Current date is $(get-date)"
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论