Input and pipes
editWrite to the standard input
// Pipe a string to stdin
var result = await ProcessWrapper.Create("cat")
.WithInputStream(InputSource.FromText("Hello, World!"))
.ExecuteBufferedAsync();
Console.WriteLine(result.Output.ToString());
// Pipe a file to stdin
var fileResult = await ProcessWrapper.Create("cat")
.WithInputStream(InputSource.FromFile("input.txt"))
.ExecuteBufferedAsync();
Console.WriteLine(fileResult.Output.ToString());
// Pipe from a TextReader
using var reader = new StringReader("Hello from reader");
var readerResult = await ProcessWrapper.Create("cat")
.WithInputStream(InputSource.FromTextReader(reader))
.ExecuteBufferedAsync();
Console.WriteLine(readerResult.Output.ToString());
// Pipe one process output to another process input
var pipe = new ProcessPipe(maxBufferSize: 256 * 1024);
var downstream = ProcessWrapper.Create("process-b")
.WithInputStream(pipe)
.ExecuteAsync();
await ProcessWrapper.Create("process-a")
.WithArguments("--generate-data")
.AddOutputStream(pipe)
.ExecuteAsync();
await downstream;WithInputStream takes an InputSource:
| Source | Created with |
|---|---|
| A string, encoded in UTF-8 | InputSource.FromText, or the string |
| Bytes | InputSource.FromBytes, or a byte[] or ReadOnlyMemory<byte> |
| A file | InputSource.FromFile |
A Stream | InputSource.FromStream, or the stream |
A TextReader, encoded in UTF-8 | InputSource.FromTextReader, or the reader |
| The output of another process | InputSource.FromProcessPipe, or a ProcessPipe |
To consume a source yourself, call ReadAsync: it reads streams, files and pipes without blocking a thread, where Read blocks until data is available.
The standard input is closed once the whole source is written, so a process that reads until the end of its input exits. Without WithInputStream, the standard input is not redirected.
Connect two processes
A ProcessPipe connects the output of one process to the input of another one, as in the last example above. Add the pipe as an output target of the first process, and as the input source of the second one. Start the reading process first, or at the same time: the pipe buffers the data written in advance, up to maxBufferSize bytes (64 KB by default), then waits for the reader to consume it.
The pipe operator
For a chain of commands, the | operator does the wiring:
var result = await (ProcessWrapper.Create("process-a")
.WithArguments("--generate-data")
| ProcessWrapper.Create("process-b")
| ProcessWrapper.Create("process-c"))
.ExecuteBufferedAsync();
// Buffered output corresponds to the last command (process-c)
foreach (var line in result.Output.StandardOutput)
{
Console.WriteLine(line.Text);
}- The standard output of each command goes to the standard input of the next one.
- ExecuteAsync and ExecuteBufferedAsync on the pipeline start every command and return the result of the last one. With ExecuteBufferedAsync, the output is the output of the last command.
- The validation of every command applies: the pipeline fails when any command fails. See Exit codes and errors.