节点派生同步命令的使用



我正在编写一个电子应用程序,该应用程序执行终端命令并将输出写入该应用程序。如果我只执行一个命令,这很容易:

const { spawn } = require('child_process');
commandOutput = document.getElementById("command-output") // textarea
status = document.getElementById("status") // div
command = "some"
args = ["command"]
dir = "some/dir"
var child = spawn(command, args, {
cwd: dir
});
child.on('error', function (err) {
commandOutput.value += 'error: <' + err + '>';
});
child.stdout.on('data', function (data) {
commandOutput.value += data;
});
child.stderr.on('data', function (data) {
commandOutput.value += 'stderr: <' + data + '>';
});
child.on('close', function (code) {
status.innerHTML = 'child process exited with code ' + code;
});

我喜欢这种方法,因为输出是流式的,而不是缓冲的,这样我就可以实时地将它写入UI,而不是等待进程完成(这可能需要一些时间(。然而,我无法找到一种方法来一个接一个地生成多个同步命令。我知道有一个命令spawnSync可以处理这个问题,但文档中没有描述如何使用它。或者,如果有更好的方法,我也对此持开放态度。

实现这一点的一种方法是在上一个命令的close事件上生成下一个命令。假设你的当前代码,你可以使用这样的东西:

child.on ("close", function (code) {
status.innerHTML = 'child process exited with code ' + code;

// Now spawn the second child
var secondChild = spawn (secondCmd, secondArgs, { cwd: dir });
secondChild.on ("error", (err) => { /* error handler */});
// Register all other handlers as well...
});

如果您更喜欢对输出进行缓冲,则可以采用这种方式。此外,您可以将所有代码生成过程放入一个函数中,并在close事件上调用该函数,就像这样:

function spawnExternalProgram (command, args, dir, next) {
// Suggestion: Clear the commandOutput field here?
var child = spawn(command, args, {
cwd: dir
});
child.on('error', function (err) {
commandOutput.value += 'error: <' + err + '>';
});
child.stdout.on('data', function (data) {
commandOutput.value += data;
});
child.stderr.on('data', function (data) {
commandOutput.value += 'stderr: <' + data + '>';
});
child.on('close', function (code) {
status.innerHTML = 'child process exited with code ' + code;
next ();
});
}
spawnExternalProgram ("some", [ "command" ], "some/dir", function () { // 1
spawnExternalProgram ("some", [ "other", "command" ], "some/dir", function () { //2
spawnExternalProgram ("yet", [ "another", "command" ], "some/dir", () => {}); // 3
});
});

一旦前一个进程退出,这将一个接一个地生成命令1、2和3。next的最后一个自变量,即() => {},等效于function () {}

正如您已经提到的,您可以选择使用spawnSync。有了这个模块,您可以通过一个函数调用一个接一个地生成进程。但是,请注意,如果您从渲染器进程生成进程,这可能会阻止您的UI。用法类似:

const { spawnSync } = require('child_process');
commandOutput = document.getElementById("command-output")
status = document.getElementById("status")
command = "some"
args = ["command"]
dir = "some/dir"
var childResultOne = spawnSync (command, args, { cwd: dir });
// Check if the process terminated:
var childOneHasTerminated = childResultOne.status === null || childResultOne.status !== 0;
// Access the stdout buffer via the childResultOne object:
var childOneOutput = childResultOne.stdout;
// ---
command = "someOther"
args = ["command", "asWell"]
dir = "some/other/dir"
// Spawn a second child process
var childResultTwo = spawnSync (command, args, { cwd: dir });
// Do all the checks as above.

请注意,只有当进程退出,即成功运行(status === 0(、终止(status === null && signal !== null(或崩溃(status !== 0(时,才会在调用spawnSync之后运行代码。这基本上就是Linux、MacOSShell或Window的cmd.exe解释Shell脚本或批处理文件的方式——一个接一个命令。

最新更新