exec和spawn
前言
需求:做一个electron应用,用node打开exe软件,打开后返回成功与否,打开的软件不会随electron应用的关闭而关闭
exec
exec
第一个参数为要运行的command命令,参数以空格分隔。
child_process.exec(command[, options][, callback])
exec
会衍生 shell,然后在该 shell 中执行 command,缓冲任何生成的输出。传递给 exec
函数的 command 字符串由 shell 直接处理,特殊字符(根据 shell 有所不同)需要进行相应处理。
例如,如果exe文件的名称中有空格,那么需要用引号包裹之后才能调用
child_process.exec(`"${appName}"`)
exec的callback 函数的参数是:error, stdout, stderr
。成功后,error
将是 null
,出错时,error
将是 Error
的实例。error.code
属性将是进程的退出码。按照惯例,除 0 之外的任何退出码都表示错误。error.signal
将是终止进程的信号。
传给回调的 stdout
和 stderr
参数将包含子进程的标准输出和标准错误的输出。默认情况下,Node.js 会将输出解码为 UTF-8 并将字符串传给回调。
const { exec } = require('node:child_process');
exec('cat *.js missing_file | wc -l', (error, stdout, stderr) => {if (error) {console.error(`exec error: ${error}`);return;}console.log(`stdout: ${stdout}`);console.error(`stderr: ${stderr}`);
});
如果把exec用util.promisify()
包裹,就会返回一个Promise
,stdout
和 stderr
是它返回的属性。如果出现错误(包括任何导致退出码不是 0 的错误),则将返回被拒绝的 Promise
,其具有与回调中给定相同的 error
对象,但有两个额外的属性 stdout
和 stderr
。
const util = require('node:util');
const exec = util.promisify(require('node:child_process').exec);try {const { stdout, stderr } = await exec('ls')console.log('stdout:', stdout);console.error('stderr:', stderr);
} catch (e) {console.error('Error:', ${(e as Error).message});
}
exec其实是封装了spawn。
spawn
异步衍生子进程,不会阻塞 Node.js 事件循环。在父 Node.js 进程和衍生的子进程之间建立 stdin、stdout 和 stderr 的管道,第一个参数为要运行command命令,参数使用字符串数组(string[])的形式传入第二个参数当中。
child_process.spawn(command[, args][, options])
options
中,使用 cwd
指定从中衍生进程的工作目录。如果没有给定,则默认是继承当前工作目录。如果给定,但路径不存在,则子进程会触发 ENOENT 错误并立即退出。当命令不存在时,也会触发 ENOENT。使用 env
指定对新进程可见的环境变量,默认为 process.env
。
const { spawn } = require('node:child_process');
const ls = spawn('ls', ['-lh', '/usr']);ls.stdout.on('data', (data) => {console.log(`stdout: ${data}`);
});ls.stderr.on('data', (data) => {console.error(`stderr: ${data}`);
});ls.on('close', (code) => {console.log(`child process exited with code ${code}`);
});
如果想使用promise的方式调用spawn,则需要借助一些库才能实现。
调用exe
传入要调用exe的绝对路径appPath
:
import { spawn } from 'child_process';
import * as path from 'path';const normalizedPath = path.normalize(appPath);
const appDir = path.dirname(normalizedPath);
const appName = path.basename(normalizedPath);
const child = spawn(`"${appName}"`, [], { shell: true, cwd: appDir, env });