【问题标题】:How to run interactive shell command inside node.js?如何在 node.js 中运行交互式 shell 命令?
【发布时间】:2015-02-12 00:59:28
【问题描述】:

我必须在 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();

这段代码不输出任何东西(但标准输出应该是2)。

但如果是这样,就会有另一个问题:如何使它具有交互性?当我打电话给pythonChildProcess.stdin.end();时,这个过程就结束了!但我只想结束stdin,写下一个stdin!

更新: 如果我可以模拟按下enter 按钮 - 我将能够以交互方式写入进程。但是在输入字符串的末尾添加\n 并没有帮助。

【问题讨论】:

  • “结束标准输入并写入下一个标准输入”?你能解释一下你的意思吗?
  • @E_net4,我想执行$ python命令,写一些输入(例如1 + 1),“按enter”,得到一些输出(2在这种情况下),然后写另一个输入(10 + 10),再次“按enter”,得到另一个输出,然后写另一个输入等等......我将这些“输入”序列命名为“stdins”跨度>
  • 这些实际上是一个标准输入流,您要向其发送多行输入。
  • inheriting 父流是微不足道的。更有趣的是actual emulation of a "headless" terminal,其中stdout被捕获为字符串,字符串被传递给子进程的stdin

标签: javascript node.js shell


【解决方案1】:

这对我很有用:

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

【讨论】:

【解决方案2】:

首先,阻止 node 与其他交互式 shell 交互的原因之一是子应用程序必须保持其“交互式”行为,即使 stdin 看起来不像终端。 python 这里知道它的 stdin 不是终端,所以它拒绝工作。这可以通过在 python 命令中添加-i 标志来覆盖。

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

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

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');

【讨论】:

  • 这只适用于python,如何让它适用于任意程序?
  • @Rainb 除了程序的名称之外,还有一个假设,即当需要用户输入时,程序的输出以换行结束。如果不是这种情况,则需要相应地调整程序。我不认为这里有灵丹妙药。考虑将您的特定问题变成一个新问题。
【解决方案3】:

@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');

输出:

> 
1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-19
    • 1970-01-01
    • 1970-01-01
    • 2016-06-14
    • 1970-01-01
    • 2012-07-12
    • 2010-09-27
    相关资源
    最近更新 更多