首页 > 解决方案 > 在 node.js 中作为子进程运行 shell(bash, zsh, sh...)

问题描述

我正在制作一个在线外壳来从另一台计算机或设备访问我的计算机。我可以运行任何程序,使用 socket.io 发送和接收 stdio 数据。我使用 child_process 中的 execFile() 运行程序。问题是,当我尝试运行 bash、sh、zsh、csh 或任何其他 shell 时,它只是不起作用,没有错误消息或任何东西。如何在 node.js 中将 shell 作为子进程运行(更喜欢使用 execFile,但这没关系)?这是我正在使用的代码:

服务器:

let fs = require("fs");
let socket = require("socket.io");
let express = require("express");
let stringio = require("@rauschma/stringio");
let childprocess = require("child_process");
let app = express();
app.use(express.static("public"));
let server = app.listen(3000);

console.log("Server running!");
let io = socket(server);
io.sockets.on("connection", connectionListener);

function connectionListener(socket) {
  console.log("New client!");
  let child = childprocess.execFile("bash", ["test.sh"], {
    stdio: [process.stdin, process.stdout, process.stderr]
  }); 
  socket.on("stdin-packet", sendtochild);
  function sendtochild(packet) {
    child.stdin.write(packet.rawtext);
  }
  child.stdout.on('data', function(data) {
    let packet = {
      rawtext: data.toString()
    };
    socket.emit("stdout-packet", packet);
    console.log("Packet sended!");
  });
}

客户:

let socket = io.connect("localhost:3000");

function TerminalScreen(width, height) {
  this.width = width;
  this.height = height;
  this.chars = "";

  this.print = function(text) {
    let isansi = false;
    for (let i = 0; i < text.length; i++) {
      if (text.charCodeAt(i) == 27) {
        isansi = true;
      } else if (text.charAt(i) == 'm' || text.charAt(i) == 'K' || text.charAt(i) == 'H' || text.charAt(i) == 'f' || text.charAt(i) == 'J') {
        if (isansi) {
          isansi = false;
        } else {
          this.chars += text.charAt(i);
        }
      } else if (!isansi) {
        this.chars += text.charAt(i);
      }
    }
    this.chars = this.chars.replace("\n", "<br>");
  }

  this.clear = function() {
    this.chars = "";
  }

  this.update = function() {
    document.getElementById("terminal-div").innerHTML = this.chars;
  }
}

let screen = new TerminalScreen();

socket.on("stdout-packet", packetReceived);

function packetReceived(packet) {
  screen.print(packet.rawtext);
  screen.update();
}

document.onkeypress = function (e) {
  e = e || window.event;
  let packet = {
    rawtext: String.fromCharCode(e.keyCode)
  };
  socket.emit("stdin-packet", packet);
};

标签: node.jsshellexpresssocketssocket.io

解决方案


最有可能的是,因为 bash 检测到它没有在伪终端 (pty) 中运行,所以它假定它是以非交互方式运行的。您可以创建一个完整的伪终端(喜欢expectssh将要做的事情),或者您可以使用-i标志强制它。


推荐阅读