Suggestion: Add redirection syntax that allows in-memory collection of stderr lines output by external utilities, akin to the -ErrorVariable common parameter
See original GitHub issueThis was first proposed as part of a lengthy exchange in #3996, but I thought it deserved its own post.
tl;dr
In order to collected stderr output (separately) from an external-utility call in memory, I suggest supporting the following new redirection syntax that allows capturing stderr lines in a variable, akin to the common -ErrorVariable
parameter for cmdlets (the sample cmd
command is designed to produce both stdout and stderr output):
# Wishful thinking: Collect stderr lines in given variable $stderrOutput via 2>&
$stdoutOutput = cmd /c ver '&' dir \nosuch 2>&stderrOutput
Instead of what you must currently do:
$stderrFile = New-TemporaryFile
$stdoutOutput = cmd /c ver '&' dir \nosuch 2>$stderrFile
$stderrOutput = Get-Content $stdErrFile
Remove-Item $stderrFile
The current behavior is to pass stderr output generated by external utility calls (e.g., to git
) through to the console - stderr output is not recorded in $Error
, which makes sense, given that many utilities write much more than just error information to stderr, and that the presence of stderr input doesn’t imply actual errors.
Sometimes it is necessary to inspect stderr output, however, which is currently not easily accomplished:
You can redirect stderr output by redirecting PowerShell’s error stream: 2>...
, but you’re faced with 2 options, neither of which is convenient:
-
Either: redirect stderr output to a file with
2>filename
-
Or: redirect stderr output into the success stream with
2>&1
to produce a combined stream from which you can later filter out the stderr lines by type ([System.Management.Automation.ErrorRecord]
).
Therefore, I propose a new redirection syntax that allows capturing stderr lines in a variable, akin to the common -ErrorVariable
parameter for cmdlets, so that:
-
foo.exe 2>&errs
would be the external-utility-call equivalent of a (fictitious)Invoke-Foo -ErrorVariable errs 2>$null
call, with errors getting collected in variable$errs
in both cases. -
Additionally, to allow stderr output to also be passed through while being collected:
foo.exe 2>&|errs
could be the equivalent ofInvoke-Foo -ErrorVariable errs
The suggestion is to use >&varName
syntax, because &
is already established as having into-a-different-target(-stream) semantics, yet currently only a digit is supported after the &
(the index of a different PS stream).
(There is still ambiguity, given that $1
is a valid variable name, but I think that wouldn’t be a real-world concern.)
Also, given that -ErrorVariable
supports a +
prefix to the variable name to indicate that the existing variable value should be appended to, this new syntax should support that too.
Environment data
PowerShell Core v6.0.0-beta.4
Issue Analytics
- State:
- Created 6 years ago
- Reactions:11
- Comments:9 (6 by maintainers)
Rather than this approach which relies on syntactic element, it was possible to create redirection as follows:
and
while not as terse as a sigil, it required very little change. It also works with native executables ala:
a further by-product is that now all streams may be redirected to a variable
and append works too
I think that using
variable:<name>
is ok - I think it’s somewhat natural for the PowerShell environment. It required a relatively simple change to the engine and a small extension toset-variable
. I can submit a PR if you think this is reasonable.I would happily vote yes to making each and every one of the numbered streams generically redirectable to any content provider PSDrive path. That makes sense, it’s always frustrating when something looks like it builds on the content providers and doesn’t.
I think a version of
Tee-Object
that could capture streams beyond should be technically impossible, because only output goes to cmdlets in a pipeline, and it would be super confusing if there was some magic thing that looked like a cmdlet but could somehow intercept other output before it gets to the host.As a use case / example: we love @dlwyatt’s PowerShellLogging module, but what it does is a dirty hack that shims the host. Unless you’re going to make interfaces public so that sort of host interception logging would be possible in every host without using private methods, I don’t need a cmdlet version of redirection, and I don’t want weird new syntax for capturing without redirecting (that is, passthrough capturing)
P.S. Alias: is a content drive and works just as well as ENV: for holding strings… 🤯