执行:显示标准输出“live”
Posted
技术标签:
【中文标题】执行:显示标准输出“live”【英文标题】:Exec : display stdout "live" 【发布时间】:2012-05-01 05:03:07 【问题描述】:我有这个简单的脚本:
var exec = require('child_process').exec;
exec('coffee -cw my_file.coffee', function(error, stdout, stderr)
console.log(stdout);
);
我只是执行一个命令来编译一个咖啡脚本文件。但是 stdout 永远不会显示在控制台中,因为命令永远不会结束(因为咖啡的 -w 选项)。 如果我直接从控制台执行命令,我会收到这样的消息:
18:05:59 - compiled my_file.coffee
我的问题是:是否可以使用 node.js exec 显示这些消息?如果是怎么办? !
谢谢
【问题讨论】:
我来这里是为了从 Python 可执行文件中捕获标准输出。请注意,以下所有内容都可以使用,但您需要使用“-u”选项运行 python,以使输出无缓冲,从而进行实时更新。 【参考方案1】:这是一个用 typescript 编写的异步辅助函数,似乎对我有用。我想这对于长期存在的进程不起作用,但对某人来说仍然很方便?
import * as child_process from "child_process";
private async spawn(command: string, args: string[]): Promise<code: number | null, result: string>
return new Promise((resolve, reject) =>
const spawn = child_process.spawn(command, args)
let result: string
spawn.stdout.on('data', (data: any) =>
if (result)
reject(Error('Helper function does not work for long lived proccess'))
result = data.toString()
)
spawn.stderr.on('data', (error: any) =>
reject(Error(error.toString()))
)
spawn.on('exit', code =>
resolve(code, result)
)
)
【讨论】:
【参考方案2】:我发现向执行此操作的实用程序添加自定义 exec 脚本很有帮助。
utilities.js
const exec = require('child_process')
module.exports.exec = (command) =>
const process = exec(command)
process.stdout.on('data', (data) =>
console.log('stdout: ' + data.toString())
)
process.stderr.on('data', (data) =>
console.log('stderr: ' + data.toString())
)
process.on('exit', (code) =>
console.log('child process exited with code ' + code.toString())
)
app.js
const exec = require('./utilities.js')
exec('coffee -cw my_file.coffee')
【讨论】:
【参考方案3】:exec
还将返回一个作为 EventEmitter 的 ChildProcess 对象。
var exec = require('child_process').exec;
var coffeeProcess = exec('coffee -cw my_file.coffee');
coffeeProcess.stdout.on('data', function(data)
console.log(data);
);
或pipe
子进程的标准输出到主标准输出。
coffeeProcess.stdout.pipe(process.stdout);
或使用 spawn 继承 stdio
spawn('coffee -cw my_file.coffee', stdio: 'inherit' );
【讨论】:
看起来这可以通过使用pipe
来简化:coffeeProcess.stdout.pipe(process.stdout);
@EricFreese 的评论正是我想要的,因为我想利用标准输出的字符替换功能(在节点脚本中使用量角器)
更简单:spawn(cmd, argv, stdio: 'inherit' )
。有关不同的示例,请参见 nodejs.org/api/child_process.html#child_process_options_stdio。
+1 表示@MorganTouvreyQuilling 建议使用spawn
和stdio: 'inherit'
。它产生比exec
和管道stdout
/stderr
更准确的输出,例如在显示来自git clone
的进度信息时。【参考方案4】:
child_process.spawn 返回一个带有 stdout 和 stderr 流的对象。 您可以点击 stdout 流来读取子进程发送回 Node.js 的数据。作为流的标准输出具有流具有的“数据”、“结束”和其他事件。 spawn 最适合用于希望子进程向 Node 返回大量数据的情况——图像处理、读取二进制数据等。
这样您就可以使用下面使用的 child_process.spawn 来解决您的问题。
var spawn = require('child_process').spawn,
ls = spawn('coffee -cw my_file.coffee');
ls.stdout.on('data', function (data)
console.log('stdout: ' + data.toString());
);
ls.stderr.on('data', function (data)
console.log('stderr: ' + data.toString());
);
ls.on('exit', function (code)
console.log('code ' + code.toString());
);
【讨论】:
【参考方案5】:已经有几个答案,但是没有一个提到最好(也是最简单)的方法,即使用spawn
和 stdio: 'inherit'
option。它似乎产生了最准确的输出,例如在显示来自git clone
的进度信息时。
只需这样做:
var spawn = require('child_process').spawn;
spawn('coffee', ['-cw', 'my_file.coffee'], stdio: 'inherit' );
感谢@MorganTouvreyQuilling 在this comment 中指出这一点。
【讨论】:
我发现当子进程使用彩色文本等格式化输出时,stdio: "inherit"
会保留该格式,而child.stdout.pipe(process.stdout)
不会。
即使在具有复杂输出的进程(例如 npm 安装上的进度条)上,它也能完美地保留输出。太棒了!
为什么这不是公认的答案?它是唯一对我有用的,它只有 2 条 f* 线!!!
这个技巧在执行一些使用进度条的 Symfony 命令行应用程序时很有帮助。干杯。
这应该是公认的答案——只有保留完美输出表示的东西并且它是最简单的?是的,请【参考方案6】:
不要使用exec
。使用 spawn
这是一个 EventEmmiter
对象。然后您可以收听 stdout
/stderr
事件 (spawn.stdout.on('data',callback..)
)发生时。
来自 NodeJS 文档:
var spawn = require('child_process').spawn,
ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', function (data)
console.log('stdout: ' + data.toString());
);
ls.stderr.on('data', function (data)
console.log('stderr: ' + data.toString());
);
ls.on('exit', function (code)
console.log('child process exited with code ' + code.toString());
);
exec
缓冲输出,通常在命令执行完成后返回。
【讨论】:
非常好。仅供参考:stdout/stderr 事件回调参数“数据”是一个缓冲区,所以用 .toString() 调用它 对于那些无法在 Windows 上工作的人来说,看看这个很棒的 answer。 exec 至少最近也是一个 EventEmitter。 还请记住,只要程序输出换行符,就不会调用回调。如果您想从子进程接收“事件”,该进程必须刷新缓冲区(C 中的flush(stdout);
)才能在 Node.js 中触发事件。
+1 on exec 也是一个 EventEmitter.. 花了 2 个小时将我的字符串重构为一个 args 数组(非常长且复杂的 ffmpeg 命令行).. 才发现我真的不需要到。【参考方案7】:
在查看了所有其他答案后,我得出了以下结论:
function oldSchoolMakeBuild(cb)
var makeProcess = exec('make -C ./oldSchoolMakeBuild',
function (error, stdout, stderr)
stderr && console.error(stderr);
cb(error);
);
makeProcess.stdout.on('data', function(data)
process.stdout.write('oldSchoolMakeBuild: '+ data);
);
有时data
将是多行,因此oldSchoolMakeBuild
标题将出现一次多行。但这并没有让我烦恼到足以改变它。
【讨论】:
【参考方案8】:受到 Nathanael Smith 的回答和 Eric Freese 的评论的启发,它可能很简单:
var exec = require('child_process').exec;
exec('coffee -cw my_file.coffee').stdout.pipe(process.stdout);
【讨论】:
这对于像ls
这样的简单命令似乎工作得很好,但对于像npm install
这样的更复杂的命令就失败了。我什至尝试将 stdout 和 stderr 都通过管道传输到它们各自的进程对象。
@linuxdan 可能是因为 npm 在 stderr 中写入(我看到有人在那里写进度条)。您还可以通过管道传输 stderr,或扩展通发解决方案以在 stderr 上侦听。
@linuxdan 我见过最可靠的方法是spawn(command, args, stdio: 'inherit' )
,这里建议***.com/questions/10232192/…
最佳答案,谢谢。像魅力一样工作【参考方案9】:
我想补充一点,使用console.log()
从生成的进程输出缓冲区字符串的一个小问题是它添加了换行符,这可以将生成的进程输出分散到其他行上。如果您使用process.stdout.write()
而不是console.log()
输出stdout
或stderr
,那么您将“按原样”从生成的进程获得控制台输出。
我在这里看到了该解决方案: Node.js: printing to console without a trailing newline?
希望对使用上述解决方案的人有所帮助(这对于实时输出来说是一个很好的解决方案,即使它来自文档)。
【讨论】:
要获得更准确的输出,请使用spawn(command, args, stdio: 'inherit' )
,正如@MorganTouvreyQuilling 在此处***.com/questions/10232192/… 所建议的那样@以上是关于执行:显示标准输出“live”的主要内容,如果未能解决你的问题,请参考以下文章
C编译二进制文件的Nodejs exec在标准输出上显示标准错误?
在linux上单独执行屏幕有输出,重定向后没有任何输出了。 myprog > 1.log 或 myprog tee 1.log