Nodejs child_process spawn get command ran
Asked Answered
I

3

13

For clarify purposes I want to see the exact command Node.js runs versus the shell/cli. Unfortunately I can't seem to find out how...

https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options

The returned object from this is an event emitter, but there's no way to sniff events from an event emitter in Nodejs at this time. I've tried data &, pipe events with no success.

The object returned with child_process.spawn has sub-objects: stdout, stdin, stderr. There's exmaples of stderr and stdout being used as event emitters & these work fine, but I can't find the events emitted by stdin...

I know I can just take my input and format it, but this feels prone to failure/inconsistency so I would much rather find a way to sniff what it is actually using.

Ingaborg answered 24/2, 2016 at 18:11 Comment(0)
T
0

There is an event for incoming data on stdin which is called "data"

process.stdin.on("data", (data) => {} );
  • While some applications process input line-by-line, other applications are more interactive and process keypresses in real time (e.g. arrow keys to move up/down a list).
  • While some applications expect plain-text, others will work with binary data.

With a wide range of possible scenarios, you are pretty much on your own here. I usually create a InputReader which just buffers all input and translates it to events that fit my specific use case.

Here follows one of the most basic examples of a reader that fires events each time a line of text is received.

export class DataReader {
  private buffer = "";

  constructor(private listener: (err, line: string)=>any ) {
  }

  processData(data) {
    // remove carriage returns, and add data to the buffer.
    data = data.toString().replace(/\r/g, '');
    this.buffer += data;

    // get only the complete data.
    const lastNewlineIndex = this.buffer.lastIndexOf('\n');
    if (lastNewlineIndex < 0) return;
    
    if (this.listener != null) {
      // split data in lines
      const completeData = this.buffer.slice(0, lastNewlineIndex);
      const lines = completeData.split('\n');
      for (const line of lines) {
        // notify listener line by line.
        this.listener(null, line);
      }
    }
    
    // remove processed data from the buffer.
    this.buffer = this.buffer.slice(lastNewlineIndex + 1);
  }
}

You could dispatch the output using an EventEmitter or some Observable in fact.

const reader = new DataReader((err, line) => subject.next(line));
process.stdin.on("data", (data) => reader.processData(data));
Transhumance answered 20/1, 2021 at 15:22 Comment(0)
P
0

Note one caveat: in the case of the current process, process.stdin is an instance of stream.Readable, and process.stdout is an instance of stream.Writable. However, in the case of a reference to a spawned child process, the situation is reversed: child.stdin is a stream.Writable, and child.stdout is a stream.Readable.

By the way, for a fan study of streams in the node, I recommend taking an interesting stream adventure course ;)

Privative answered 27/3 at 12:25 Comment(0)
S
-1

The problem here is that stdin is a write only unix socket. You can write to the childs stdin, but if you want to detect any sort of format, it will have to happen on the data event of stdout.

your app ----> stdin of child (can only write to it)

your app <---- stdout of child (can only read from it)

I hope I explained my view it your satisfaction? If not, give me an example of why you want to see what stdin messages are arriving on an external program. (if there is a way, then I suspect all you will get back is the same data your write to it)

Skylar answered 7/8, 2018 at 18:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.