简体   繁体   English

NodeJS PTY 计时命令

[英]NodeJS PTY timing commands

I'm trying to use a node process to kick off an interactive docker session then automate some commands to it:我正在尝试使用节点进程来启动交互式 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');

This seems to work, the only issue is it seems like it's just writing in all the commands and firing them.这似乎有效,唯一的问题是它似乎只是写入所有命令并触发它们。 I don't seem to have any control over catching the output or errors of individual commands.我似乎无法控制捕获单个命令的输出或错误。

I'm curious if there's a better way to approach this?我很好奇是否有更好的方法来解决这个问题?

You can pipe streams to this process, however it is not advised to do so.您可以通过管道将流传输到此进程,但不建议这样做。

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

The maintainer have suggested to not use pty in like a stream. 维护者建议不要像流一样使用 pty。 It's simply a matter of changing the pipeline for something like this.这只是为这样的事情改变管道的问题。

(async (stream) => {
  for await (const chunk of stream) {
    proc.write(chunk.toString())
  }
})(process.stdin).catch(console.warn)

The gist is that we should pass string into the write function.要点是我们应该将字符串传递给 write 函数。 We also should expect string as its output.我们也应该期待字符串作为它的输出。 Therefore, we should not set any encoding in the object so that it by default outputs utf8 string.因此,我们不应在对象中设置任何编码,使其默认输出 utf8 字符串。

Regarding your initial question.关于你最初的问题。 proc.write('ls\\r') is the correct way of doing it. proc.write('ls\\r')是正确的做法。 Note the trailing \\r to virtually press enter.请注意尾随\\r以虚拟按 Enter。 Just like in a normal terminal, when you execute a command, you cannot fire a second one simultaneously.就像在普通终端中一样,当您执行一个命令时,您不能同时触发第二个命令。 The commands will just queue up and run one after another.这些命令只会排队并一个接一个地运行。

Input:输入:

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()
})

Output:输出:

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
...
...
# 

You see it wrote ls before npm install was completed but it ran afterwards.你看到它在 npm install 完成之前写了 ls 但它之后运行了。

Also note that I used -ti instead of just -t for the docker args.另请注意,对于 docker args,我使用了-ti而不是-t

Looking through the source for the pty.js module, it is clear that your proc.write is really the standard Node net.Socket.write -- https://nodejs.org/api/net.html#net_socket_write_data_encoding_callback查看pty.js模块的源代码,很明显您的proc.write确实是标准的 Node net.Socket.write -- https://nodejs.org/api/net.html#net_socket_write_data_encoding_callback

In short, yes, you are just spamming the commands to the socket.简而言之,是的,您只是将命令发送到套接字。 You need to wait for each command to finish before executing the next.在执行下一个命令之前,您需要等待每个命令完成。 Thus, you'll need to use the callback parameter of .write to determine when a command has finished and then proceed from there.因此,您需要使用.write的回调参数来确定命令何时完成,然后从那里继续。 Something like this may work:像这样的事情可能会奏效:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM