如何从node.js打开terminal应用程序?

我希望能够从terminal上运行的node.js程序打开Vim ,创build一些内容,保存并退出Vim ,然后抓取文件的内容。

我正在尝试做这样的事情:

 filename = '/tmp/tmpfile-' + process.pid editor = process.env['EDITOR'] ? 'vi' spawn editor, [filename], (err, stdout, stderr) -> text = fs.readFileSync filename console.log text 

但是,当这个运行,它只是挂起terminal。

我也试着用exec得到相同的结果。

更新:

这个过程很复杂,因为这个过程是通过在readline运行的提示符下键入的命令启动的。 我完全将我最新版本的相关部分提取到一个文件中。 这是完整的:

 {spawn} = require 'child_process' fs = require 'fs' tty = require 'tty' rl = require 'readline' cli = rl.createInterface process.stdin, process.stdout, null cli.prompt() filename = '/tmp/tmpfile-' + process.pid proc = spawn 'vim', [filename] #cli.pause() process.stdin.resume() indata = (c) -> proc.stdin.write c process.stdin.on 'data', indata proc.stdout.on 'data', (c) -> process.stdout.write c proc.on 'exit', () -> tty.setRawMode false process.stdin.removeListener 'data', indata # Grab content from the temporary file and display it text = fs.readFile filename, (err, data) -> throw err if err? console.log data.toString() # Try to resume readline prompt cli.prompt() 

它的工作方式如上所示,它显示一个提示几秒钟,然后启动到Vim,但TTY是搞砸了。 我可以编辑,并保存文件,内容打印正确。 在出口处还有一堆垃圾被打印到terminal,并且Readlinefunction在之后被打破(没有向上/向下箭头,没有选项卡完成)。

如果我取消cli.pause()行的注释,那么TTY在Vim中是可以的,但是我插入模式, Esc键不起作用。 如果我Ctrl-C它会退出subprocess和父进程。

更新:我的答案在创build时应用,但是对于现代版本的Node,请看这个答案 。

首先,你使用的产卵是不正确的。 这里是文档。 http://nodejs.org/docs/latest/api/child_processes.html#child_process.spawn

你的示例代码看起来像你期望VIM自动popup和接pipeterminal,但它不会。 要记住的重要一点是,即使您可能产生一个进程,您也需要确保将进程中的数据传送到您的terminal进行显示。

在这种情况下,你需要从stdin中获取数据并发送给vim,并且你需要把vim输出的数据设置到你的terminal上,否则你什么都看不到。 您还需要将tty设置为原始模式,否则节点将截取某些键序列,因此vim将无法正常运行。

接下来,不要做readFileSync。 如果你遇到了一个你认为需要使用同步方法的情况,那么很可能是,你做错了什么。

以下是我放在一起的一个简单例子。 我不能保证它在每一个案件中工作,但它应该涵盖大部分案件。

 var tty = require('tty'); var child_process = require('child_process'); var fs = require('fs'); function spawnVim(file, cb) { var vim = child_process.spawn( 'vim', [file]) function indata(c) { vim.stdin.write(c); } function outdata(c) { process.stdout.write(c); } process.stdin.resume(); process.stdin.on('data', indata); vim.stdout.on('data', outdata); tty.setRawMode(true); vim.on('exit', function(code) { tty.setRawMode(false); process.stdin.pause(); process.stdin.removeListener('data', indata); vim.stdout.removeListener('data', outdata); cb(code); }); } var filename = '/tmp/somefile.txt'; spawnVim(filename, function(code) { if (code == 0) { fs.readFile(filename, function(err, data) { if (!err) { console.log(data.toString()); } }); } }); 

更新

我见过 我不认为readline与所有这一切是一致的,因为你不幸的是。 问题是,当你创build接口时,节点types假设它将从这个点完全控制那个stream。 当我们将数据redirect到vim时,readline仍然在处理按键,但是vim也在做同样的事情。

我看到的唯一方法是在启动vim之前手动禁用cli界面中的所有内容。

就在你产生这个过程之前,我们需要closures这个接口,不幸的是我们手动删除了这个按键监听器,因为至less在这个时候,节点不会自动的将它移除。

 process.stdin.removeAllListeners 'keypress' cli.close() tty.setRawMode true 

然后在进程“退出”callback中,您将需要再次调用createInterface。

只从主进程inheritancestdio。

 var editor = process.env.EDITOR || 'vi'; var child = child_process.spawn(editor, ['/tmp/somefile.txt'], { stdio: 'inherit' }); child.on('exit', function (e, code) { console.log("finished"); }); 

更多选项: http : //nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options