Read child process I/O
I want to write a simple Deno CLI script using
Deno.Command
or dx
that can read output from a shell utility.
For example, gum input --placeholder=\"Enter your name\"
displays a small text input, which I want to read the user input into Deno.
- If I use a Deno.Command
stdout: "inherit"
, then Deno doesn't have access to the stdout stream (containing the user name), just the file signal.
- So I tried stdout: "piped"
and piping the streams – but then the terminal hangs and displays nothing.
Does this use look right?:
2 Replies
When using
Deno.Command
to spawn a subprocess and interact with its I/O streams, it's important to understand how the stdin
, stdout
, and stderr
options work. According to the documentation, if you set stdout
to "piped"
, you can access the output of the subprocess as a ReadableStream
. However, if you set stdout
to "inherit"
, the subprocess will inherit the standard output of the parent process, and you won't be able to programmatically read the output because it's directly written to the terminal.
In your case, you want to read the output from the gum
utility, so setting stdout
to "piped"
is correct. However, there are a few things to consider in your code snippet:
1. You are piping Deno.stdin.readable
to process.stdin
, which means you're trying to forward the input from the Deno process to the gum
utility. If gum
is expecting input from the user, this might not be necessary unless you want to programmatically send input to gum
.
2. You are piping process.stdout
to Deno.stdout.writable
and process.stderr
to Deno.stderr.writable
. This should forward the output and error streams from gum
to the Deno process's standard output and error streams, respectively.
3. It's important to close the stdin
of the subprocess if you're done sending input. According to the documentation, if stdin
is set to "piped"
, the stdin
WritableStream
needs to be closed manually.
Here's a revised version of your code snippet that takes these points into account:
```ts
const cmd = new Deno.Command("gum", {
args: [
"input",
"--placeholder="Enter your name"",
],
stdout: "piped", // We want to read the output programmatically
stderr: "piped", // We want to read the error output programmatically
});
const process =cmd.spawn();
// Assuming we don't need to send input to gum, we don't pipe Deno.stdin to process.stdin
// If you do need to send input, uncomment the following line and ensure to close process.stdin when done
// Deno.stdin.readable.pipeTo(process.stdin);
// Forward the output of gum to Deno's stdout
const stdoutPromise = process.stdout.pipeTo(Deno.stdout.writable);
// Forward the error output of gum to Deno's stderr
const stderrPromise = process.stderr.pipeTo(Deno.stderr.writable);
// Wait for both piping operations to complete
await Promise.all([stdoutPromise, stderrPromise]);
// Get the exit status of the subprocess
const status = await process.status;
console.log("Process exited with code:", status.code);
``
Remember to handle the case where
gum` might not produceHelpful Links:
Subprocesses: Spawning - Deno by Example
Subprocesses: Collecting Output - Deno by Example
Deno 1.29: Custom npm registry support
Deno 1.21 Release Notes
Deno 1.24 Release Notes
Deno 1.x to 2.x Migration Guide | Deno Docs
Deno 1.19 Release Notes
Deno.Command | Runtime APIs | Deno
Creating a Subprocess | Deno Docs