开发工具【免费下载链接】execaProcess execution for humans项目地址https://gitcode.com/gh_mirrors/ex/execa点击查看免费下载本指南以 execa 官方 READMEreadme.md为核心骨架结合仓库源码与测试展开。Execa 运行你脚本、应用或库中的命令与 shell 不同它专门为编程化使用programmatic usage而优化构建于 Node.js 核心模块child_process之上。读完本文你将掌握 execa 的模板字符串语法、$脚本接口、本地二进制执行、多进程管道、输入输出类型转换、IPC 消息通信、优雅终止以及调试与自定义日志等完整实战能力。一、项目定位为人类而生的进程执行Execa 的口号是Process execution for humans。它把 Node.js 底层child_process繁琐的spawn/exec/fork调用包装成简洁、类型安全、Promise 化的高层 API并针对程序化调用场景做了大量优化这一点在 docs/bash.md 中有专门对比说明。从 package.json 可以看到当前仓库版本为10.0.1要求Node.js 22采用 ESMtype: module规范通过exports字段暴露typesindex.d.ts与defaultindex.js入口内置依赖包括get-stream、npm-run-path、signal-exit、strip-final-newline、yoctocolors等这些依赖分别服务于流式收集输出、本地二进制路径解析、退出清理、去换行与彩色输出等底层能力。二、安装npm install execa安装后即可在 ESM 项目中直接导入import {execa} from execa;三、核心特性总览Execa 的 Features 清单既是能力地图也是本文后续各节的索引简单语法Promise 模板字符串类似zx的体验。脚本接口$命令提供更贴近 shell 的书写方式。免转义免引号无需 escaping 与 quoting从设计上杜绝 shell 注入风险详见 docs/escaping.md。本地二进制无需npx即可执行项目本地安装的 CLI 工具。增强的 Windows 支持正确处理 shebang、PATHEXT、优雅终止等详见 docs/windows.md。详细错误、verbose 模式与自定义日志服务于调试详见 docs/debugging.md。多子进程管道可获取中间结果、支持多源/多目标与 unpipe详见 docs/pipe.md。输出切分/迭代按文本行切分或渐进迭代。去除多余换行详见 docs/lines.md。任意输入类型文件、字符串、Uint8Array、迭代器、对象乃至几乎任意其他类型分别参见 docs/input.md、docs/binary.md、docs/streams.md、docs/transform.md。任意输出类型或将输出重定向到文件。交错输出stdout与stderr按终端真实打印顺序交错合并。编程式与终端输出并存一边在代码中获取结果一边打印到控制台。输入输出变换/过滤用简单函数即可实现docs/transform.md。Node.js 流与 Web 流互操作或将子进程转换为流docs/streams.md。子进程消息通信docs/ipc.md。保证子进程退出即使它拦截了终止信号或当前进程意外结束docs/termination.md。四、文档地图Execa 的官方文档按主题拆分为独立章节是深入学习每个特性的权威入口执行类基本执行、转义/引号、Shell、脚本、Node.js 文件、环境、错误、终止。输入输出类输入、输出、文本行、二进制数据、变换。高级用法多子进程管道、流、进程间通信、调试、Windows、与 Bash/zx 的差异、精简包、TypeScript、API 参考。五、执行示例5.1 简单语法模板字符串execa可直接以标签模板字符串调用命令无需引号包裹参数插值也无需手动转义import {execa} from execa; const {stdout} await execanpm run build; // 打印命令输出 console.log(stdout);从源码看这一语法糖由 lib/methods/template.js 中的parseTemplates()实现它会判断传入参数是否带raw属性的模板数组isTemplateString将其解析为[file, commandArguments, {}]形式再交给统一核心执行。模板表达式${expression}支持字符串与数字也支持直接插入上一个子进程的结果对象如${subprocess}的stdout若误插入未await的 Promise 或ChildProcess会抛出TypeError提示请使用 ${await subprocess} 而不是 ${subprocess}。5.2 脚本接口$$接口与execa等价但预置了脚本友好的默认选项。按 lib/methods/script.js 的实现当未指定input、inputFile与stdio时$会自动设置stdin: inherit并且preferLocal: true作为深层次选项在管道场景中对两个命令都生效import {$} from execa; const {stdout: name} await $cat package.json.pipegrep name; console.log(name); const branch await $git branch --show-current; await $dep deploy --branch${branch}; await Promise.all([ $sleep 1, $sleep 2, $sleep 3, ]); const directoryName foo bar; await $mkdir /tmp/${directoryName};注意最后一行目录名含空格但模板插值让 execa 将其作为单个参数传递无需任何引号或转义。$还提供同步变体$.sync与别名$.s由setScriptSync挂载。5.3 本地二进制无需 npx安装项目本地依赖后用preferLocal: true选项即可直接执行无需npx前缀$ npm install -D eslintawait execa({preferLocal: true})eslint;底层由npm-run-path库见 lib/arguments/options.js 的getEnv()在preferLocal或node: true时自动拼接node_modules/.bin到 PATH 环境变量中从环境层面实现本地优先解析。5.4 管道多个子进程管道返回的 Promise 会解析为目标子进程的结果同时通过pipedFrom保留每一级中间结果const {stdout, pipedFrom} await execanpm run build .pipesort .pipehead -n 2; // 相当于 npm run build | sort | head -n 2 的输出 console.log(stdout); // 相当于 npm run build | sort 的输出 console.log(pipedFrom[0].stdout); // 相当于 npm run build 的输出 console.log(pipedFrom[0].pipedFrom[0].stdout);管道能力由 lib/pipe/setup.js 的pipeToSubprocess()驱动它把源子进程的stdout/stderr/stdio接到目标子进程的stdin并Promise.race两个子进程的完成与 unpipe 中止信号.pipe()返回值还会转发目标的stdio、all、可迭代方法以及 IPC 方法sendMessage、getOneMessage、getEachMessage。对比 shell 管道execa 的优势是能拿到中间结果、支持一个源接多个目标、多个源接一个目标以及按需 unpipe详见 docs/pipe.md。六、输入输出示例6.1 交错输出allall: true时返回结果的all字段包含stdout与stderr按实际打印顺序交错合并的内容const {all} await execa({all: true})npm run build; // stdout stderr 交错 console.log(all);该流由 lib/resolve/all-async.js 的makeAllStream()创建同时收集两个通道并按时间顺序合并。6.2 编程式输出 终端输出stdout选项设为[pipe, inherit]时输出既被 execa 捕获供程序读取又同时打印到终端const {stdout} await execa({stdout: [pipe, inherit]})npm run build; // stdout 也会打印到终端 console.log(stdout);inherit意味着子进程直接复用父进程的标准流参见 docs/output.md 与 stdio 选项文档 docs/api.md。6.3 简单输入const getInputString () { /* ... */ }; const {stdout} await execa({input: getInputString()})sort; console.log(stdout);字符串输入会写入子进程的stdin并在结束后关闭详见 docs/input.md。6.4 文件输入 / 文件输出// 类似: npm run build input.txt await execa({stdin: {file: input.txt}})npm run build; // 类似: npm run build output.txt await execa({stdout: {file: output.txt}})npm run build;stdin/stdout 支持{file: path}形式的文件描述对象由 lib/stdio/stdio-option.js 及 stdio 处理器展开为文件重定向。6.5 按文本行切分const {stdout} await execa({lines: true})npm run build; // 打印前 10 行 console.log(stdout.slice(0, 10).join(\n));lines: true时stdout从字符串变为字符串数组并自动去除行尾换行符。从 lib/arguments/options.js 看lines生效还需满足编码为非二进制且buffer开启两个前提条件。相关实现见 lib/io/strip-newline.js 与 lib/io/iterate.js。七、流式处理示例7.1 逐行迭代子进程本身可直接被for await...of迭代逐行处理输出for await (const line of execanpm run build) { if (line.includes(WARN)) { console.warn(line); } }迭代由 lib/convert/iterable.js 的createIterable()实现返回一个Symbol.asyncIterator按行产出文本相关测试见 test/io/iterate.js 与 test/stdio/iterable.js。7.2 转换/过滤输出stdout选项可接收一个生成器函数对每一行做变换或过滤let count 0; // 先过滤掉包含 secret 的行再为每行加上行号前缀 const transform function * (line) { if (!line.includes(secret)) { yield [${count}] ${line}; } }; await execa({stdout: transform})npm run build;变换管线的核心位于 lib/transform/run-async.js、lib/transform/run-sync.js 与 lib/transform/split.js生成器按文本行切分输入逐个yield转换后的行写回目标流。完整能力参见 docs/transform.md。7.3 Web 流直接传入fetch返回的ReadableStream作为stdinconst response await fetch(https://example.com); await execa({stdin: response.body})sort;Web 流支持由 lib/convert/web.js 提供可把 Web 流、Node 流与子进程的 stdio 统一起来。7.4 转换为 Duplex 流子进程可通过.duplex()转换为双工流与node:stream/promises的pipeline无缝衔接import {execa} from execa; import {pipeline} from node:stream/promises; import {createReadStream, createWriteStream} from node:fs; await pipeline( createReadStream(./input.txt), execanode ./transform.js.duplex(), createWriteStream(./output.txt), );duplex()由 lib/convert/duplex.js 实现本质是把子进程stdin作为可写端、stdout作为可读端封装成PassThrough类双工流仓库还提供readable()、writable()、readableStream()、writableStream()、transformStream()等转换方法见 lib/convert/add.js。八、进程间通信IPC8.1 交换消息父进程与子进程可通过 promise 化的 API 双向发消息子进程侧用execaNode启动以保证 IPC 通道开启// parent.js import {execaNode} from execa; const subprocess execaNodechild.js; await subprocess.sendMessage(Hello from parent); const message await subprocess.getOneMessage(); console.log(message); // Hello from child// child.js import {getOneMessage, sendMessage} from execa; const message await getOneMessage(); // Hello from parent const newMessage message.replace(parent, child); // Hello from child await sendMessage(newMessage);IPC 实现分两条链路父进程侧由 lib/ipc/methods.js 的addIpcMethods()把sendMessage/getOneMessage/getEachMessage挂到子进程对象上子进程侧通过getIpcExport()导出同名函数。消息发送在 lib/ipc/send.js单条读取在 lib/ipc/get-one.js逐条迭代在 lib/ipc/get-each.js。8.2 任意输入类型ipcInputipcInput允许传入包含正则、Set等复杂结构的对象数组作为子进程输入且自动开启ipc// main.js import {execaNode} from execa; const ipcInput [ {task: lint, ignore: /test\.js/}, {task: copy, files: new Set([main.js, index.js]), }]; await execaNode({ipcInput})build.js;// build.js import {getOneMessage} from execa; const ipcInput await getOneMessage();从 lib/arguments/options.js 的addDefaultOptions()可以看到默认ipc ipcInput ! undefined || gracefulCancel即一旦传入ipcInput或启用优雅取消IPC 通道自动打开消息序列化默认采用serialization: advanced这也是能传输RegExp、Set等类型的原因lib/ipc/ipc-input.js 负责校验。8.3 任意输出类型ipcOutput子进程侧多次sendMessage的结构化消息会按序汇入父进程结果的ipcOutput数组// main.js import {execaNode} from execa; const {ipcOutput} await execaNodebuild.js; console.log(ipcOutput[0]); // {kind: start, timestamp: date} console.log(ipcOutput[1]); // {kind: stop, timestamp: date}// build.js import {sendMessage} from execa; const runBuild () { /* ... */ }; await sendMessage({kind: start, timestamp: new Date()}); await runBuild(); await sendMessage({kind: stop, timestamp: new Date()});8.4 优雅终止gracefulCancel通过AbortController与gracefulCancel: true组合可在取消时让子进程优雅收尾——先通知子进程自行清理而非立刻强杀// main.js import {execaNode} from execa; const controller new AbortController(); setTimeout(() { controller.abort(); }, 5000); await execaNode({ cancelSignal: controller.signal, gracefulCancel: true, })build.js;// build.js import {getCancelSignal} from execa; const cancelSignal await getCancelSignal(); const url https://example.com/build/info; const response await fetch(url, {signal: cancelSignal});取消相关的校验与执行逻辑在 lib/terminate/cancel.js校验cancelSignal必须是AbortSignal并在中止时触发kill()与 lib/terminate/graceful.js子进程侧通过getCancelSignal()拿到取消信号见 lib/ipc/graceful.js。完整终止语义参见 docs/termination.md。九、调试与日志9.1 详细错误对象命令失败时抛出的ExecaError同步版为ExecaSyncError定义于 lib/return/final-error.js携带极其丰富的诊断字段import {execa, ExecaError} from execa; try { await execaunknown command; } catch (error) { if (error instanceof ExecaError) { console.log(error); } /* ExecaError: Command failed with ENOENT: unknown command spawn unknown ENOENT at ... at ... { shortMessage: Command failed with ENOENT: unknown command\nspawn unknown ENOENT, originalMessage: spawn unknown ENOENT, command: unknown command, escapedCommand: unknown command, cwd: /path/to/cwd, durationMs: 28.217566, failed: true, timedOut: false, isCanceled: false, isTerminated: false, isMaxBuffer: false, code: ENOENT, stdout: , stderr: , stdio: [undefined, , ], pipedFrom: [] [cause]: Error: spawn unknown ENOENT at ... at ... { errno: -2, code: ENOENT, syscall: spawn unknown, path: unknown, spawnargs: [ command ] } } */ }错误对象在 lib/return/result.js 的makeError()中组装包含command/escapedCommand、退出码code、stdout/stderr/stdio快照、是否超时/取消/超缓冲等标志原始 spawn 错误则作为error.cause保留。完整错误语义见 docs/errors.md。9.2 Verbose 模式不附加任何配置连续运行多个命令时execa 会自动输出分步、分色的执行日志命令、时长、退出码等await execanpm run build; await execanpm run test;运行效果示意如下仓库 media/verbose.pngverbose 输出的生成与格式控制分布在 lib/verbose/ 目录start.js、complete.js、output.js、error.js、ipc.js等相关测试见 test/verbose/。9.3 自定义日志verbose选项可传入回调函数将 execa 的事件流接入任意日志框架示例使用 Winstonimport {execa as execa_} from execa; import {createLogger, transports} from winston; // 用 Winston 将日志写入文件 const transport new transports.File({filename: logs.txt}); const logger createLogger({transports: [transport]}); const LOG_LEVELS { command: info, output: verbose, ipc: verbose, error: error, duration: info, }; const execa execa_({ verbose(verboseLine, {message, ...verboseObject}) { const level LOG_LEVELS[verboseObject.type]; loggerlevel; }, }); await execanpm run build; await execanpm run test;注意这里通过execa_(options)预先绑定选项生成新的execa实例——这正是 lib/methods/create.js 中options binding能力的体现当createExeca生成的函数收到一个纯对象作为首个参数时它会合并选项并返回一个绑定了这些默认选项的嵌套版本。verbose回调的type字段涵盖command、output、ipc、error、duration等事件类型可据此映射日志级别参见 lib/verbose/custom.js。十、与其他方案的区别Execa 被定位为编程化进程执行工具与交互式 shell 脚本有本质区别核心差异包括详见 docs/bash.md基于 Promise所有命令都可await、可并行、可组合天然融入异步代码流。模板字符串代替拼接参数以数组形式传递空格、特殊字符无需引号消除注入面。结构化结果与错误返回包含stdout/stderr/exitCode/durationMs的对象错误也是可编程检查的结构。本地二进制优先自动解析node_modules/.bin省去npx。跨平台一致对 Windows 的 shebang、PATHEXT做了兼容处理docs/windows.md。类型安全完整的 TypeScript 类型定义见 types/ 与 test-d/类型级测试保证编译期发现错误用法。十一、小结Execa 用统一的 Promise API 覆盖了进程执行的全场景从最基础的execa/execaSync/execaNode/$四种入口导出定义见 index.js到模板字符串解析lib/methods/template.js、选项归一化与默认值lib/arguments/options.js、异步核心执行lib/methods/main-async.js、流式转换lib/transform/、管道编排lib/pipe/、IPC 消息lib/ipc/与终止控制lib/terminate/再配合详细的错误对象与可定制日志让你以接近 shell 的简洁、远超 shell 的可靠性完成进程编排。深入每个主题时官方文档见上文文档地图与仓库内 test/ 目录下的对应测试用例都是最佳参考资料。赞分享开发工具【免费下载链接】execaProcess execution for humans项目地址https://gitcode.com/gh_mirrors/ex/execa点击查看免费下载相关推荐Execa 基础执行完全指南数组语法、模板字符串语法与返回值详解Execa 基础执行完全指南数组语法、模板字符串语法与返回值详解 ExecaProcess execution for humans是构建在 Node.j开发工具基于 PHP 可变函数与字符串转义的远程命令执行与 WAF 绕过实战指南webshell 仓库配套基于 PHP 可变函数与字符串转义的远程命令执行与 WAF 绕过实战指南webshell 仓库配套 本篇技术指南以仓库文档 How To Exploit P网络安全渗透测试TypeScript 模板字符串Template Literals实战指南插值、多行与标签模板TypeScript 模板字符串Template Literals实战指南插值、多行与标签模板 导读 模板字符串Template Literals又称教程上一篇MediaMTX 定时抓帧快照基于 runOnAvailable 钩子 FFmpeg 的流截图方案下一篇【亲测免费】 VRM-Addon-for-Blender 项目推荐创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考