-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Description
Currently, stdin input streamed to pwsh from the outside:
-
does not automatically become pipeline input;
- accessing stdin input currently requires constructing a separate pipeline in PowerShell code using
$Input
- accessing stdin input currently requires constructing a separate pipeline in PowerShell code using
-
only automatically becomes input to interactive prompts, such as
Read-Hostcalls or the automatic prompts displayed when mandatory arguments are missing.
This has the following implications:
You cannot directly pipe data to PowerShell commands from the outside:
Contrast the following two commands:
# Bash:
# stdin input is "relayed" to the 'wc' utility
$ printf 'one\ntwo' | bash -c 'wc'
2# PowerShell:
PS> printf 'one\ntwo' | pwsh -noprofile -c 'Measure-Object -Word | % Words'
0 # !! Measure-Object did NOT receive stdin input.
# Explicit reference to $Input in an internal pipeline is required:
PS> printf 'one\ntwo\n' | pwsh -noprofile -c '$Input | Measure-Object -Word | % Words'
2printf 'one\ntwo\n' | pwsh -noprofile -c 'Measure-Object -Word'
If you're calling an advanced script that binds pipeline input, it cannot be invoked with just -File, because it won't receive pipeline input:
# Create an advanced script that echoes each pipeline input enclosed in [...]
'[CmdletBinding()] param([Parameter(ValueFromPipeline)] $var) process { "[$var]" }' > t.ps1
# Call from either Bash or PowerShell (same behavior).
PS> echo hi | pwsh -noprofile -file t.ps1
[] # !! t.ps1 did NOT receive stdin input
# The workaround is again non-obvious and cumbersome:
PS> echo hi | pwsh -noprofile -command '$Input | ./t.ps1'
[hi] # OKSimilarly, if you author a pipeline-binding advanced script as shebang-line-based script on Unix, it cannot receive stdin input directly:
# Create a shebang-line-based script...
@'
#!/usr/bin/env pwsh
[CmdletBinding()] param([Parameter(ValueFromPipeline)] $var) process { "[$var]" }
'@ > foo
# ... and make it executable.
chmod +x foo
# Call from either Bash or PowerShell (same behavior).
PS> 1..2 | ./foo
[] # !! Pipeline input wasn't bound, not even with pipeline input from PowerShell.PowerShell's behavior here is at odds with traditional shells and arguably makes the typical use case unnecessarily difficult.
Note: I'm unclear on whether this can be fixed without breaking existing behavior.
The challenge is to know when to provide stdin input via an implied PowerShell pipeline, and when to use stdin input line by line, on demand, to respond to interactive prompts.
E.g., the following currently works - the two distinct Read-Host prompts are "answered" by 1 stdin input line each:
$ 'one\ntwo\n' | pwsh -noprofile -c 'read-host first; get-date; read-host second'
first: one
one
Monday, April 29, 2019 10:52:04 AM
second: two
twoEnvironment data
PowerShell Core 6.2.0
Metadata
Metadata
Assignees
Labels
Type
Projects
Status