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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27458502/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 07:31:09  来源:igfitidea点击:

How to run interactive shell command inside node.js?

javascriptnode.jsshell

提问by Wunsch Punsch

I have to run some interactive shell command inside node.js. Lets our interactive shell be $ python:

我必须在 node.js 中运行一些交互式 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();

This code does not output anything (but stdout should be 2).

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

But if it would, there will be another problem: how to make it interactive? The process ends when I call pythonChildProcess.stdin.end();! But I just wanted to end stdin and write next stdin!

但如果是这样,就会出现另一个问题:如何使其具有交互性?当我打电话时,过程结束pythonChildProcess.stdin.end();!但我只想结束标准输入并编写下一个标准输入!

UPD: If I could emulate pressing of enterbutton - I would be able to interactively write to the process. But adding \nto the end of the input string does not help.

UPD:如果我可以模拟按下enter按钮 - 我将能够以交互方式写入该过程。但是添加\n到输入字符串的末尾无济于事。

采纳答案by E_net4 the Rustacean

First and foremost, one of the things preventing node from interfacing with other interactive shells is that the child application must keep its "interactive" behavior, even when stdindoesn't look like a terminal. pythonhere knew that its stdinwasn't a terminal, so it refused to work. This can be overridden by adding the -iflag to the python command.

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

Second, as you well mentioned in the update, you forgot to write a new line character to the stream, so the program behaved as if the user didn't press Enter. Yes, this is the right way to go, but the lack of an interactive mode prevented you from retrieving any results.

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

Here's something you can do to send multiple inputs to the interactive shell, while still being able to retrieve each result one by one. This code will be resistant to lengthy outputs, accumulating them until a full line is received before performing another instruction. Multiple instructions can be performed at a time as well, which may be preferable if they don't depend on the parent process' state. Feel free to experiment with other asynchronous structures to fulfil your goal.

您可以执行以下操作将多个输入发送到交互式 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');

回答by Adam

This works great for me:

这对我很有用:

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

回答by Jayant Bhawal

A tl;dr version of @E_net4's answer, for those who understand just by reading the code. For a detailed explanation, please do read his answer. He has described it well.

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

Output:

输出:

> 
1