我编写了一个类,用于生成和与shell交互(在电子应用程序中),如下所示:
const { spawn } = require('child_process')
class Shell {
constructor() {
this.process = spawn('/bin/bash', []);
this.process.stdout.on('data', (data) => {
const out = data.toString()
console.log('stdout:', out)
if (this.res) {
this.res(out)
}
});
this.process.stderr.on('data', function (data) {
const err = data.toString()
console.log('stderr:', err)
if (this.rej) this.rej(err)
});
}
send(command, throwErr = false) {
return new Promise((resolve, reject) => {
this.res = resolve
if (throwErr) this.rej = reject
else this.rej = resolve
this.process.stdin.write(command + 'n')
})
}
}
我得到的输出是:
stdout: ]0;student@linux-opstation-jyrf: ~[01;32mstudent@linux-opstation-jyrf[00m:[01;34m~[00m$
这里是一个版本,我用JSON将输出字符串化以查看转义字符:stdout: "u001b]0;student@linux-opstation-jyrf: ~u0007u001b[01;32mstudent@linux-opstation-jyrfu001b[00m:u001b[01;34m~u001b[00m$ ssh -t -t -oStrictHostKeyChecking=no student@10.5r50.30.231rn"
我意识到这些是bash转义序列用于格式化的工件,我很难弄清楚如何摆脱它,特别是因为转义字符不被打印。
编辑:所以我将原始标准输出Buffer
(代码中的data
)写入二进制文件:
fs.createWriteStream(path, { encoding: 'binary'}).write(data);
,发现似乎没有损失发生在.toString()
方法(我认为?),所以我留下抓耳挠头,其余的stdout标记被截断。
00000000: 1b5d 303b 7374 7564 656e 7440 6c69 6e75 .]0;student@linu
00000010: 782d 6f70 7374 6174 696f 6e2d 6a79 7266 x-opstation-jyrf
00000020: 3a20 7e07 1b5b 3031 3b33 326d 7374 7564 : ~..[01;32mstud
00000030: 656e 7440 6c69 6e75 782d 6f70 7374 6174 ent@linux-opstat
00000040: 696f 6e2d 6a79 7266 1b5b 3030 6d3a 1b5b ion-jyrf.[00m:.[
00000050: 3031 3b33 346d 7e1b 5b30 306d 2420 7373 01;34m~.[00m$ ss
00000060: 6820 2d74 202d 7420 2d6f 5374 7269 6374 h -t -t -oStrict
00000070: 486f 7374 4b65 7943 6865 636b 696e 673d HostKeyChecking=
00000080: 6e6f 2073 7475 6465 6e74 4031 302e 350d no student@10.5.
00000090: 3530 2e33 302e 3233 310d 0a 50.30.231..
但是当我保存文件时,也许我没有得到正确的编码,因为我认为原始缓冲区应该(?)输出文本,如u001b[00m:u001b[01;34m
和uFFFF
十六进制字符不存在。编辑:啊,uFFFF
显然是unicode。仍然在弄清楚如何将缓冲区正确地保存为二进制,我认为unicode正在丢失{encoding: 'binary'}
设置为选项。或者十六进制转储只显示utf8,这听起来更有可能。
假设这些工件确实来自自定义的提示字符串,那么最简单的事情就是更改提示字符串。有多种替代方法,这在一定程度上取决于提示字符串的设置位置。
如果你得到一个提示,那么bash
是作为一个交互式shell运行的。它不会以登录shell的形式运行,并使用您用来启动它的命令。相应的初始化步骤如下:
当一个非登录shell的交互式shell被启动时,bash从
~/.bashrc
(如果该文件存在)读取并执行命令。这可以使用——norc选择。——rcfilefile
选项将强制bash从文件中读取和执行命令,而不是~/.bashrc
.
(Bash手册)
因此,您可以将--norc
选项传递给bash
,以抑制读取任何shell初始化文件,从而获得默认提示(以及默认的其他一切)。但是,对于您的需求来说,该环境可能过于稀疏,因此,作为一种替代方法,您可以创建一个专门的shell配置文件来设置您想要的确切配置,并使用--rcfile
选项使程序启动的bash
实例使用该配置。这可能是你最好的选择,但是可能需要一些工作来设置你需要的
作为一种更快更脏的替代方法,您可以修改相关的~/.bashrc
来更改提示字符串(删除PS1
和PS2
的定义,或者将它们重新定义为默认值:PS1='s-v$ ' PS2='> '
)。您还可以将前面两个配置文件与一个自定义配置文件结合使用,该文件读取默认配置文件并覆盖提示字符串:
electron.bashrc
. ~/.bashrc
PS1='s-v$ '
PS2='> '
这是一个粗糙、丑陋、快速的解决方案。我欢迎更优雅的方法:
const { spawn } = require('child_process')
class Shell {
constructor() {
// I just threw a bunch of output into a regex tester
// and wrote `|` joined matches until all markup in my
// sample input was detected. That's all there is to it.
// This will almost certainly not work across various
// machines depending on how the markup is structured.
const re = /\u[0-9 a-f]{4}[dd;ddm|\u[0-9 a-f]{4}]0;|\u[0-9 a-f]{4}[ddm:\u[0-9 a-f]{4}[dd;ddm|\u[0-9 a-f]{4}[ddm|\u[0-9 a-f]{4}/g
this.process = spawn('/bin/bash', []);
this.process.stdout.on('data', (data) => {
const out = data.toString()
const stringified = JSON.stringify(out)
console.log('stdout:', stringified)
const trimmed = stringified.replace(re, "")
.split('"').join('')
.split('\r').join('')
.split('\n').join('')
console.log('parsed stdout:', trimmed)
if (this.res) {
this.res(out)
}
});
this.process.stderr.on('data', function (data) {
const err = data.toString()
console.log('stderr:', err)
if (this.rej) this.rej(err)
});
}
send(command, throwErr = false) {
return new Promise((resolve, reject) => {
this.res = resolve
if (throwErr) this.rej = reject
else this.rej = resolve
this.process.stdin.write(command + 'n')
})
}
}