Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
311 views
in Technique[技术] by (71.8m points)

pipeline - Piping a string into a cmd does not work in PowerShell script

I have the following working call when I execute it directly in my PowerShell window:

$myexe = "C:MyExe.exe"
"MyString" | & $myexe // works
Write-Output "MyString" | & $myexe // seems to work too

However, when I perform the same in a function of a PowerShell script it does no longer work. The program does not receive the string...any ideas?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Unlike POSIX-compatible shells such as bash, PowerShell does not automatically relay pipeline input received by a given script or function to commands you call from inside that script or function.

To do so, you must use the automatic $input variable[1]:

For instance:

function foo {
  # Relay the pipeline input received by this function 
  # to an external program, using `cat` as an example.
  $input | & /bin/cat -n # append $args to pass options through
}

'MyString' | foo

Note that & is optional in this case, because /bin/cat is an unquoted, literal path - see this answer for when & is required.

The output (on a Unix-like platform) is: 1 MyString, showing that the cat utility received the foo function's own pipeline input via its stdin, thanks to use of $input.

Without piping $input to cat, the latter would receive no stdin input at all (and in the case of cat would block, waiting for interactive input).

If you want to support passing filename arguments too - in lieu of pipeline input - more work is needed:

function foo {
  if ($MyInvocation.ExpectingInput) { # Pipeline input present
    # Relay the pipeline input received by this function 
    # to an external program, using `cat` as an example.
    $input | /bin/cat -n $args
  } else { # NO pipeline input.
    /bin/cat -n $args
  }
}

'MyString' | foo  # pipeline input
foo file.txt      # filename argument

Note:

  • Only non-advanced functions and scripts can make use of the $input variable, and its use implies that all input piped to the enclosing function/script is collected in full, up front, before sending it on begins.

  • To truly stream a script / function's own pipeline input to a single invocation of an external program - i.e. to relay the input as it is being received by the script / function - requires direct use of .NET APIs, namely System.Diagnostics.ProcessStartInfo and System.Diagnostics.Process.


[1] Similarly, $input is required to access data piped to a PowerShell command from outside PowerShell, via PowerShell's CLI; e.g., from bash:
echo hi | pwsh -c '$input | ForEach-Object { "[{0}]" -f $_ }'


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...