exec ,execFile,spawn 都是运行一个子进程,但是在不同的操作系统上用法和表现有很大差异。

linux/unix

exec运行子进程需要创建一个终端环境(命令行窗口),然后在其中运行命令,execFile则不需要,因此在linux/unix上,execFile的效率更高。

windows

在windows平台上,运行脚本程序(如批处理.bat)必须有一个终端环境(命令行窗口),因此无法使用execFile,只能使用exec和spawn。

exec总是会创建一个新出的终端环境,并在这个终端中运行命令。spawn不需要创建一个新的终端环境,而是直接运行进程并监事进程输出内容。

exec通常用于运行时间较短的命令,spawn通常用于运行长时间运行的命令。exec一次性获取程序输出内容,spawn可以持续获取程序的输出流。

在windows上,exec和spawn都可以借助cmd.exe命令来运行子进程。

// On Windows Only...
const { spawn } = require('node:child_process');
const bat = spawn('cmd.exe', ['/c', 'my.bat']);

bat.stdout.on('data', (data) => {
  console.log(data.toString());
});

bat.stderr.on('data', (data) => {
  console.error(data.toString());
});

bat.on('exit', (code) => {
  console.log(`Child exited with code ${code}`);
});

或者

// OR...
const { exec, spawn } = require('node:child_process');
exec('my.bat', (err, stdout, stderr) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log(stdout);
});

// Script with spaces in the filename:
const bat = spawn('"my script.cmd"', ['a', 'b'], { shell: true });
// or:
exec('"my script.cmd" a b', (err, stdout, stderr) => {
  // ...
});

关闭子进程

nodejs帮助文档给的例子很简单:

const { spawn } = require('node:child_process');
const grep = spawn('grep', ['ssh']);

grep.on('close', (code, signal) => {
  console.log(
    `child process terminated due to receipt of signal ${signal}`);
});

// Send SIGHUP to process.
grep.kill('SIGHUP');

但是在windows平台上,使用这个方法通常无法关闭,可以采用如下方法:

const { spawn } = require('node:child_process');
const grep = spawn('grep', ['ssh']);

grep.on('exit', (code) => {
  console.log(
    `child process terminated with code ${code}`);
});

// kill process. On Windows Only...
let pid = grep.pid;
exec(`taskkill /PID ${pid} /T /F`, (error, stdout, stderr)=>{
	console.log("taskkill stdout: " + stdout)
  console.log("taskkill stderr: " + stderr)
  if(error){
      console.log("error: " + error.message)
  }
 });