NodeJS PTY定时命令

时间:2015-09-12 18:53:40

标签: javascript node.js pty

我尝试使用节点进程启动交互式docker会话,然后自动执行一些命令:



var spawn = require('pty.js').spawn;

var proc = spawn('docker', [ 'run', '-i', '-t', 'mycontainer' ], {
  name: 'test',
  rows: 30,
  cols: 200,
  cwd: process.env.HOME,
  env: process.env
});

proc.on('data', function (data) {
  console.log(data);
});

proc.write('cd /tmp');
proc.write('nvm install 0.10\r');
proc.write('npm install');




这似乎有效,唯一的问题是它似乎只是在所有命令中编写并解雇它们。我似乎无法控制捕获单个命令的输出或错误。

我很好奇是否有更好的方法来解决这个问题?

2 个答案:

答案 0 :(得分:1)

您可以通过管道将流传输到此过程,但是不建议这样做。

#include <stdio.h>
#include <cs50.h>
int main(void)
{
int i , j , k , Height ;
Height = get_int("Enter desired pyramid height between 1 and 8: ");
while (!((Height<=8 && (Height>=1)))
{
    Height = get_int("Enter desired pyramid height between 1 and 8: ");
}
if (Height>0 && Height<9)
{
for (i=0;i<Height;i++)
{
    for(j=0;j<(Height-1-i);j++)
    {
        printf(" ");
    }
    for(k=i+1;k>0;k--)
    {
        printf("#");
    }
    printf("  ");
    for(k=i+1;k>0;k--)
    {
        printf("#");
    }
    printf("\n");
}
}
}

不要像流一样使用pty的maintainer have suggested。只需更改类似这样的管道即可。

const { pipeline } = require('stream');
const { spawn } = require('node-pty')

const proc = spawn('docker', ['run', '--rm', '-ti', 'alpine', '/bin/sh'], {
  name: 'xterm-color',
  cwd: process.env.HOME,
  env: process.env,
  encoding: null,
});

pipeline(process.stdin, proc, (err) => err && console.warn(err.message))
pipeline(proc, process.stdout, (err) => err && console.warn(err.message))

要点是我们应该将字符串传递给write函数。我们还应该期望将字符串作为其输出。因此,我们不应在对象中设置任何编码,以便默认情况下它会输出utf8字符串。

关于您最初的问题。 (async (stream) => { for await (const chunk of stream) { proc.write(chunk.toString()) } })(process.stdin).catch(console.warn) 是正确的方法。注意尾随proc.write('ls\r')以虚拟方式按Enter。就像在普通终端中一样,当您执行命令时,不能同时触发第二个命令。这些命令只会排队并一个接一个地运行。

输入:

\r

输出:

const { spawn } = require('node-pty')

const proc = spawn('docker', ['run', '--rm', '-ti', '--network=host', 'node', '/bin/sh'], {
  name: 'xterm-color',
  cwd: process.env.HOME,
  env: process.env,
});

proc.write('npm init -y\r')
proc.write('npm i eslint\r')
proc.write('ls node_modules /\r')

const disposable = proc.onData((text) => process.stdout.write(text))

const exitDisposable = proc.onExit(() => {
  disposable.dispose()
  exitDisposable.dispose()
})

您看到它在npm安装完成之前写了ls,但是后来运行了。

还请注意,我为码头工人参数使用了npm i eslint ls node_modules / # Wrote to /package.json: { "name": "", "version": "1.0.0", "description": "", "main": "index.js", "directories": { "lib": "lib" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" } npm notice created a lockfile as package-lock.json. You should commit this file. npm WARN @1.0.0 No description npm WARN @1.0.0 No repository field. + eslint@7.1.0 added 136 packages from 82 contributors and audited 136 packages in 9.461s 9 packages are looking for funding run `npm fund` for details found 0 vulnerabilities # /: bin etc lib64 node_modules package.json run sys var boot home media opt proc sbin tmp dev lib mnt package-lock.json root srv usr node_modules: @babel is-extglob @types is-fullwidth-code-point ... ... # 而不是-ti

答案 1 :(得分:0)

查看pty.js模块的来源,很明显您的proc.write确实是标准节点net.Socket.write - https://nodejs.org/api/net.html#net_socket_write_data_encoding_callback

简而言之,是的,您只是将命令垃圾邮件发送到套接字。在执行下一个命令之前,您需要等待每个命令完成。因此,您需要使用.write的回调参数来确定命令何时完成,然后从那里继续。这样的事情可能有用:

// this is a quick and dirty hack
let cmdcount = 0;

function submitcmd() {
  switch (cmdcount) {
    case 0:
      proc.write('nvm install 0.10\r', 'utf8', submitcmd);
      break;
    case 1:
      proc.write('npm install', 'utf8', submitcmd);
      break;
  }

  cmdcount += 1;
}

proc.write('cd /tmp', 'utf8', submitcmd);