9

I'd think this would be simple, but the following does not work as expected.

I want to pipe data to a process, say (just an arbitrary command for illustration) wc, from Node.

The docs and other SO questions seem to indicate that passing a Stream should work:

const {spawnSync} = require('child_process')
const {Readable} = require('stream')

const textStream = new Readable()
textStream.push("one two three")
textStream.push(null)

const stdio = [textStream, process.stdout, process.stderr]
spawnSync('wc', ["-c"], { stdio })

Unfortunately this throws an error:

The value "Readable { ... } is invalid for option "stdio"

The relevant bit of code from internal/child_process.js does not immediately reveal what the anticipated valid options are.

Brian M. Hunt
  • 81,008
  • 74
  • 230
  • 343
  • This is quite intriguing! I've only managed to make it work by passing data directly to the `input` option instead of reassigning `stdin`. – E_net4 Jul 03 '17 at 18:38
  • _"Note that the stream must have an underlying descriptor"_. I don't think your `textStream` has one. – robertklep Jul 03 '17 at 19:31
  • Thanks @robertklep — I noted that, too; from all I've read it isn't clear why a descriptor is needed, how it's implemented/differentiated from a regular stream, or in any case how one works around it. It's a strange, seemingly arbitrary requirement. – Brian M. Hunt Jul 03 '17 at 19:39
  • It's not arbitrary, because that's how pipelines (which is basically what you're trying to build) work: they connect file descriptors. The combination of piping data to a process and `spawnSync` doesn't really make sense either, though, because the external program is executed synchronously (so you can't pipe anything to it in between it being started and it ending). Perhaps you want to use the `input` option? – robertklep Jul 03 '17 at 19:44
  • Thanks @robertklep – the `input` options looks like the correct answer here. Aside: the correct solution should be IMHO that `stdio[0]` should be valid on any compliant implementation of a abstract stream interface; be it from a socket, file, pipe, or any other readable interface; the synchronicity of the spawn is a `wait` for the spawn to exit — but that does not inhibit the spawned process from e.g. reading forever from stdin. The limitation to streams with descriptors seems to be an arbitrary technical caveat, not a principled design choice to serve a rational objective. Could be wrong :) – Brian M. Hunt Jul 03 '17 at 23:48
  • @robertklep Please feel free to post your answer (the `input` option) and I will mark it correct — and it will make more visibility for future readers who encounter the same. – Brian M. Hunt Jul 04 '17 at 12:16

1 Answers1

10

To present particular data as stdin data for the child process, you can use the input option:

spawnSync('wc', ['-c'], { input : 'one two three' })
robertklep
  • 198,204
  • 35
  • 394
  • 381