How do you connect two (pipe stdin and stdout) Deno subprocesses?
Asked Answered
V

2

10

Judging by the API docs, a Deno subprocess (an instance of Deno.Process) can receive one of four stdin types, the same goes for stdout. However, there's no mention in the documentation as to how to pipe the output from one subprocess to the input of another. What I'm trying to achieve is akin to the basic UNIX pipe (oneProcess | another) and then read the output of the second process in the pipeline. Simply running

const someProcess = Deno.run({
  cmd: ["oneProcess firstParameter | another 2ndParameter"]
});

fails with an error of:

error: Uncaught NotFound: No such file or directory (os error 2)

because the first argument (string) is expected to be an executable.

How would one achieve this is Deno then, are we required to perhaps set "piped" as both the output and input to the subprocesses (respectively) and then manually read and write data from one to another?

Veradia answered 29/5, 2020 at 14:19 Comment(3)
Yeah, the first one, imagine that I'd want to run a process, pipe the output of that process to the second one and then read the output from the second process.Veradia
Got it, now I see the error, my bad. Thought you got the issue with oneProcess not existing. I'll post an answer in a bit.Oster
Let me know if my answer is what you wanted.Oster
O
10

You're getting NotFound: no such file or directory because the value passed to cmd must be a path to the binary.

the first element needs to be a path to the binary

And onProcess | another is not a binary.


To use a unix pipe | you can run bash and then write to stdin.

const p = Deno.run({
  cmd: ["bash"],
  stdout: "piped",
  stdin: "piped"
});

const encoder = new TextEncoder();
const decoder = new TextDecoder();

const command = "echo -n yes | md5sum";
await p.stdin.write(encoder.encode(command));

await p.stdin.close();
const output = await p.output()
p.close();

console.log(decoder.decode(output)); // a6105c0a611b41b08f1209506350279e
Oster answered 29/5, 2020 at 14:36 Comment(0)
S
6

For anyone from the future where Deno.run() is deprecated, here's one way to do it with Deno.Command() (as of Deno 1.37.2). I took the same example as the accepted answer.

/* 
    How to 'echo "hello world" | md5sum' in Deno (1.37.2) with Deno.Command()

    example.ts
*/

// our commands
const echo = new Deno.Command('echo', { args: ['hello world'], stdout: 'piped' }).outputSync()
const md5sum = new Deno.Command('md5sum', { stdin: 'piped', stdout: 'piped' }).spawn()

// pipe whatver our first stdout was to the next stdin
const writer = md5sum.stdin.getWriter()

// let Deno do the thing
await writer.write(echo.stdout)
await writer.ready
await writer.close()

// do whatever with the final stdout
const md5sum_out = await md5sum.output()

// there it is =>  6f5902ac237024bdd0c176cb93063dc4
console.log('there it is => ', new TextDecoder().decode(md5sum_out.stdout))

// depending on the commands we might need this to not block Deno...
md5sum.unref()

Don't forget to run with the --allow-run command but beware!

The --allow-run permission is required for creation of a subprocess. Be aware that subprocesses are not run in a Deno sandbox and therefore have the same permissions as if you were to run the command from the command line yourself.

deno run --allow-run example.ts
Swint answered 24/10, 2023 at 15:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.