如何在node.js中运行交互式shell命令?

Wun*_*sch 13 javascript shell node.js

我必须在node.js中运行一些交互式shell命令.让我们的交互式shell $ python:

var cp = require('child_process');
var pythonChildProcess = cp.spawn('python');

pythonChildProcess.stdout.on("data", function(data) {
  console.log('data successfully written!', data); // never outputs anything
});

pythonChildProcess.stdin.write('1 + 1');
pythonChildProcess.stdin.end();
Run Code Online (Sandbox Code Playgroud)

此代码不输出任何内容(但应该是stdout 2).

但如果它会,那将会有另一个问题:如何让它互动?我打电话过程结束pythonChildProcess.stdin.end();!但我只是想结束stdin并写下一个stdin!

UPD:如果我可以模仿按下enter按钮 - 我将能够以交互方式写入该过程.但是添加\n到输入字符串的末尾并没有帮助.

Ada*_*dam 20

这对我很有用:

const { spawn } = require('child_process')
const shell = spawn('sh',[], { stdio: 'inherit' })
shell.on('close',(code)=>{console.log('[shell] terminated :',code)})
Run Code Online (Sandbox Code Playgroud)

  • 正是我一直在寻找的东西! (4认同)
  • 完美的解决方案。 (2认同)
  • 那将是`stdio:'继承'`。您可以在此处阅读不同的选项:https://nodejs.org/api/child_process.html#child_process_options_stdio (2认同)
  • 我必须添加 `{ stdio: 'inherit', shell: true }` 才能让它为我们工作。看起来它至少可以在 MacOS 和 Windows 上运行。 (2认同)

Jay*_*wal 6

@E_net4 答案的 tl;dr 版本,供那些只需阅读代码即可理解的人使用。有关详细解释,请阅读他的回答。他描述得很好。

var spawn = require('child_process').spawn

var p = spawn('node',['-i']);

p.stdout.on('data',function (data) {
    console.log(data.toString())
});

p.stdin.write('1 + 0\n');
Run Code Online (Sandbox Code Playgroud)

输出:

> 
1
Run Code Online (Sandbox Code Playgroud)


E_n*_*ate 5

首先,阻止节点与其他交互式shell连接的一个原因是子应用程序必须保持其"交互"行为,即使stdin看起来不像终端.python在这里知道它stdin不是终端,所以它拒绝工作.可以通过向-ipython命令添加标志来覆盖它.

其次,正如您在更新中提到的那样,您忘记在流中写入新行字符,因此程序的行为就像用户没有按Enter键一样.是的,这是正确的方法,但缺乏交互模式阻止您检索任何结果.

您可以执行以下操作,将多个输入发送到交互式shell,同时仍然可以逐个检索每个结果.该代码将抵抗冗长的输出,累积它们直到在执行另一条指令之前接收到完整的行.也可以一次执行多个指令,如果它们不依赖于父进程的状态,则这可能是优选的.随意尝试其他异步结构来实现您的目标.

var cp = require('child_process');
var childProcess = cp.spawn('python', ['-i']);

childProcess.stdout.setEncoding('utf8')

var k = 0;
var data_line = '';

childProcess.stdout.on("data", function(data) {
  data_line += data;
  if (data_line[data_line.length-1] == '\n') {
    // we've got new data (assuming each individual output ends with '\n')
    var res = parseFloat(data_line);
    data_line = ''; // reset the line of data

    console.log('Result #', k, ': ', res);

    k++;
    // do something else now
    if (k < 5) {
      // double the previous result
      childProcess.stdin.write('2 * + ' + res + '\n');
    } else {
      // that's enough
      childProcess.stdin.end();
    }
  }
});


childProcess.stdin.write('1 + 0\n');
Run Code Online (Sandbox Code Playgroud)