nodejs脚本中如何执行shell命令

 更新时间:2025年02月06日 10:02:15   作者:Amber.Li  
Node.js中使用child_process模块的exec和spawn方法来执行shell命令,exec适合执行小命令,返回输出;spawn适合大命令或长时间运行的命令,实时输出

官方文档:

Node.js v8.x 中文文档:child_process - 子进程

Node.js中使用内置的child_process模块来执行shell命令。该模块提供了exec、execFile、spawn等方法来启动子进程并执行命令

一:exec 方法执行shell命令

1. 注意:

  • exec 方法是将整个命令输出缓存到内存中,当执行完成后一次性返回,所以适合执行较小的命令
  • exec 方法的回调函数只有在命令执行完成后才会被调用[持续性命令会导致回调函数不执行]

第2点_举例:

npm run dev

该命令会一直运行,而 exec 方法的回调函数只有在命令运行完成后才会被调用,导致你的回调函数一直没有返回

2. 优点特性:

  • 优点是简单易用,方便地执行简单的命令,并且可以直接获取命令输出;
  • 阻塞式调用的,当命令输出很大时,可能会导致阻塞程序的执行,甚至会导致程序崩溃

3. 语法格式

exec( '命令',option对象, 回调函数callback);

4. option对象属性

  • cwd <string> 子进程的当前工作目录。
  • env <Object> 环境变量键值对。
  • encoding <string> 默认为 ‘utf8’。
  • shell <string> 执行命令的 shell。在 UNIX 上默认为 ‘/bin/sh’,在 Windows 上默认为 process.env.ComSpec。详见Shell的要求与Windows默认的Shell。
  • timeout <number> 默认为 0。
  • maxBuffer <number> stdout 或 stderr 允许的最大字节数。默认为 200*1024。如果超过限制,则子进程会被终止。详见 maxBuffer与Unicode。
  • killSignal <string> | <integer> 默认为 ‘SIGTERM’。
  • uid<number>设置进程的用户标识,详见 setuid(2)。
  • gid<number>设置进程的组标识,详见 setgid(2)。
  • windowsHide <boolean> 隐藏子进程的控制台窗口,常用于 Windows 系统。默认为 false。

5. _示例:

Nodejs–标识Node.js进程运行其上的操作系统平台: process.platform

const { exec } = require('child_process');

 // 就是进行简单`判断`在执行环境下应该使用`哪个命令行`执行命令;
 // process.platform : 标识Node.js进程运行其上的操作系统平台
 // 返回值:‘aix',‘darwin',‘freebsd',‘linux',‘openbsd',‘sunos',‘win32'
 
exec('ls -la',{shell:process.platform === 'win32'}, (error, stdout, stderr) => {
  if (error) {
    console.error(`执行出错: ${error}`);
    return;
  }
  console.log(`stdout: ${stdout}`);
  console.error(`stderr: ${stderr}`);
});

回调函数有三个参数:

error、stdout和stderr:

  • error表示执行命令时出现的错误;
  • stdout表示命令的标准输出;
  • stderr表示命令的标准错误输出;

二:spawn 方法 执行shell命令

1. 注意:

  • spawn方法执行的命令参数应该是一个Array。
  • 这样可以避免shell注入攻击.
// 命令参数应该是一个`数组`  ['-la']
const ls = spawn('ls', ['-la'],{shell:process.platform === 'win32'},);

2. 优点特性:

spawn 方法则是实时返回子进程的标准输出和标准错误流,适合执行大量数据或者长时间运行的命令[ 例如 npm run dev ];

异步执行的,可以在命令输出时即时处理数据,不会阻塞程序的执行;

可以灵活地配置子进程的输入输出、环境变量等选项

3. _语法格式:

const ls = spawn(命令String, 命令参数Array,option对象);

ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

ls.stderr.on('data', (data) => {
  console.error(`stderr: ${data}`);
});

ls.on('close', (code) => {
  console.log(`子进程退出码:$[code]`);
});

4. option对象属性

  • cwd <string> 子进程的当前工作目录。
  • env<Object>环境变量键值对。
  • argv0 <string> 显式地设置要发给子进程的 argv[0] 的值。 如果未指定,则设为 command。
  • stdio<Array> | <string>子进程的 stdio 配置。 (详见 options.stdio)
  • detached <boolean> 准备将子进程独立于父进程运行。 具体行为取决于平台。(详见 [options.detached])
  • uid <number> 设置该进程的用户标识。(详见 setuid(2))
  • gid <number> 设置该进程的组标识。(详见 setgid(2))
  • shell <boolean> | <string> 如果为 true,则在一个 shell 中运行 command。 在 UNIX 上使用 '/bin/sh',在 - Windows 上使用 process.env.ComSpec。 一个不同的 shell 可以被指定为字符串。 See [Shell Requirements][] and [Default Windows Shell][]. 默认为 false(没有 shell)。
  • windowsVerbatimArguments <boolean> 决定在Windows系统下是否使用转义参数。 在Linux平台下会自动忽略,当指令 shell 存在的时该属性将自动被设置为true。默认值: false。
  • windowsHide 是否隐藏在Windows系统下默认会弹出的子进程控制台窗口。 默认为: false。

【4.1 】 .stdio 属性详解 :配制在父进程和子进程之间建立的管道

  • 配制在父进程和子进程之间建立的管道
  • 影响到 shell 命令,或者 node 命令 在控制台上的输出

【属性值格式 <Array> | <string> 】

['pipe', 'pipe', 'pipe'] (默认值)

数组元素按位置分别对应:

  • - stdin [命令的标准输入]
  • - stdout [命令的标准输出]
  • - stderr [执行命令时出现的错误]

'pipe', 'ignore', 'inherit

作用
pipe父进程中通过 child_process.spawn.stdout.on(“data”, () => {}) 等获取
ignore父进程通过管道得到的是 null
inherit子进程将使用父进程的标准输入输出
	ls.stdout.on('data', (data) => {
	  console.log(`stdout: ${data}`);
	});
	
	ls.stderr.on('data', (data) => {
	  console.error(`stderr: ${data}`);
	});
	
	ls.on('close', (code) => {
	  console.log(`子进程退出码:$[code]`);
	});

5. 示例:

const { spawn } = require('child_process');

// 就是进行简单`判断`在执行环境下应该使用`哪个命令行`执行命令;
// process.platform : 标识Node.js进程运行其上的操作系统平台
// 返回值:‘aix',‘darwin',‘freebsd',‘linux',‘openbsd',‘sunos',‘win32'

const ls = spawn('ls', ['-la'],{shell:process.platform === 'win32'},);

ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

ls.stderr.on('data', (data) => {
  console.error(`stderr: ${data}`);
});

ls.on('close', (code) => {
  console.log(`子进程退出码:$[code]`);
});

如果需要执行一个复杂的shell命令:

可以使用sh命令,并将命令字符串作为参数传递给sh命令;

例如:

const { spawn } = require('child_process');

const command = 'ls -la | grep "example"';

const sh = spawn('sh', ['-c', command]);

sh.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

sh.stderr.on('data', (data) => {
  console.error(`stderr: ${data}`);
});

sh.on('close', (code) => {
  console.log(`子进程退出码:$[code]`);
});

示例中:

  • 我们使用sh命令执行了一个包含管道的shell命令,并将该命令字符串作为参数传递给sh命令。
  • 在spawn方法中,我们使用['-c', command]作为参数来启动sh命令

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 使用puppeteer破解极验的滑动验证码

    使用puppeteer破解极验的滑动验证码

    这篇文章主要介绍了利用puppeteer破解极验的滑动验证功能,基本流程代码实现给大家介绍的非常详细,需要的朋友可以参考下
    2018-02-02
  • nvm管理node无法正常切换node版本问题的解决方法

    nvm管理node无法正常切换node版本问题的解决方法

    相信一定会有存在一些小伙伴 明明都已经按着操作卸载node 和安装nvm 了但是 依旧无法正常通过nvm管理node,本文将给大家介绍nvm管理node无法正常切换node版本问题的解决方法,需要的朋友可以参考下
    2024-01-01
  • nodejs 实现钉钉ISV接入的加密解密方法

    nodejs 实现钉钉ISV接入的加密解密方法

    这篇文章主要介绍了nodejs 实现钉钉ISV接入的加密解密方法,非常不错,具有参考借鉴价值,需要的的朋友参考下吧,需要的朋友可以参考下
    2017-01-01
  • node.JS的crypto加密模块使用方法详解(MD5,AES,Hmac,Diffie-Hellman加密)

    node.JS的crypto加密模块使用方法详解(MD5,AES,Hmac,Diffie-Hellman加密)

    本文将详细介绍node.JS的加密模块crypto实现MD5,AES,Hmac,Diffie-Hellman加密的详解方法,需要的朋友可以参考下
    2020-02-02
  • Node.js与npm版本兼容性问题的原因及解决方案

    Node.js与npm版本兼容性问题的原因及解决方案

    在现代 Web 开发中,Node.js 和 npm 是不可或缺的工具,然而,随着 Node.js 和 npm 的快速发展,版本之间的兼容性问题逐渐成为开发者面临的常见挑战,本文将深入探讨 Node.js 和 npm 版本兼容性问题,分析其产生的原因,并提供解决方案和最佳实践,需要的朋友可以参考下
    2025-01-01
  • 如何用node优雅地打印全链路日志

    如何用node优雅地打印全链路日志

    这篇文章主要给大家介绍了关于如何用node优雅地打印全链路日志的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-03-03
  • Nodejs Sequelize手册学习快速入门到应用

    Nodejs Sequelize手册学习快速入门到应用

    这篇文章主要为大家介绍了Nodejs Sequelize手册学习快速入门到应用,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • 深入浅析Node.js 事件循环、定时器和process.nextTick()

    深入浅析Node.js 事件循环、定时器和process.nextTick()

    这篇文章主要介绍了Node.js 事件循环、定时器和process.nextTick()的相关知识,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-10-10
  • package.json版本号符号^和~前缀的区别

    package.json版本号符号^和~前缀的区别

    这篇文章介绍了package.json版本号符号^和~前缀的区别,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • 浅谈Nodejs中的作用域问题

    浅谈Nodejs中的作用域问题

    在JS中有全局作用域和函数作用域,而在Nodejs中也自己的作用域,分为全局作用域(global)和模块作用域。本文将对Nodejs中的作用域进行介绍,需要的朋友一起来看下吧
    2016-12-12

最新评论