tinyexec📟
用于执行命令的最小包
创建这个包是为了提供与child交互的最小方式 无需手动处理流、管道等的进程。
安装
$ npm i -S tinyexec
用法
一个进程可以像这样被生成和等待:
import {x} from 'tinyexec';
const result = await x('ls', ['-l']);
// result.stdout - the stdout as a string
// result.stderr - the stderr as a string
// result.exitCode - the process exit code as a number
默认情况下,tinyexec不会抛出非零退出码。检查 result.exitCode 或通过 {throwOnError: true}。
输出完全按照生成的方式返回;尾随换行符不会被修剪。如果你需要修剪,明确地做:
const clean = result.stdout.replace(/\r?\n$/, '');
你也可以通过异步循环遍历输出的行:
import {x} from 'tinyexec';
const proc = x('ls', ['-l']);
for await (const line of proc) {
// line will be from stderr/stdout in the order you'd see it in a term
}
选项
可以通过传递选项来更好地控制进程的生成:
await x('ls', [], {
timeout: 1000
});
options对象可以有以下属性:
signal——一个AbortSignal允许中止执行timeout强制终止进程的时间(以毫秒为单位)persist——如果true,该进程将在主机退出后继续stdin-string或另一个Result这将被用作流程的输入nodeOptions-任何有效的选项到节点的底层spawn函数throwOnError-如果为true,非零退出码将抛出错误nodePath——如果false,node_modules/.bin目录和当前节点可执行文件的目录将不会被附加到PATH(默认为true)
将字符串传递给stdin
你可以传递一个字符串给 stdin,这对于空白敏感值和不应该在shell历史记录中暴露的秘密非常有用:
const result = await x('gh', ['auth', 'login', '--with-token'], {
stdin: process.env.GITHUB_TOKEN
});
console.log(result.exitCode);
管道连接到另一个进程
可以将一个进程管道到另一个进程 pipe 方法:
const proc1 = x('ls', ['-l']);
const proc2 = proc1.pipe('grep', ['.js']);
const result = await proc2;
console.log(result.stdout);
pipe 采用与常规执行相同的选项。例如,你可以
将超时传递给管道调用:
proc1.pipe('grep', ['.js'], {
timeout: 2000
});
终止进程
你可以通过 kill 方法:
const proc = x('ls');
proc.kill();
// or with a signal
proc.kill('SIGHUP');
节点模块/二进制文件
默认情况下,节点的可用二进制文件 node_modules 将是可访问的
在你的指挥下。
例如,在回购中 eslint 安装:
await x('eslint', ['.']);
在这个例子中, eslint 会来自本地安装吗 node_modules。
如果你不愿意的话 node_modules/.bin (或目录的当前
node 可执行的)附加到 PATH,通过 nodePath: false:
await x('eslint', ['.'], {nodePath: false});
使用中止信号
可以将中止信号传递给进程,以便稍后中止该进程
时间。这将导致进程被终止并 aborted 被设置
来 true。
const aborter = new AbortController();
const proc = x('node', ['./foo.mjs'], {
signal: aborter.signal
});
// elsewhere...
aborter.abort();
await proc;
proc.aborted; // true
proc.killed; // true
使用命令字符串
如果您需要继续以字符串形式支持命令(例如:“command arg0 arg1”), 你可以用 args-tokenizer, 用于将shell命令字符串解析为数组的轻量级库。
import {x} from 'tinyexec';
import {tokenizeArgs} from 'args-tokenizer';
const commandString = 'echo "Hello, World!"';
const [command, ...args] = tokenizeArgs(commandString);
const result = await x(command, args);
result.stdout; // Hello, World!
同步
你可以用 xSync 对于同步(阻塞)执行:
import {xSync} from 'tinyexec';
const result = xSync('ls', ['-l']);
// result.stdout - the stdout as a string
// result.stderr - the stderr as a string
// result.exitCode - the process exit code as a number
像异步API一样,你可以遍历行:
const result = xSync('ls', ['-l']);
for (const line of result) {
// line will be from stdout then stderr
}
由于同步API阻塞了事件循环,所以异步API中支持的一些特性是同步API不支持的:
signalpersistkill()方法stdin管道pipe()方法
其他选项如 timeout, throwOnError, nodeOptions 以同样的方式工作。
API
调用 x(command[, args]) 返回一个可等待对象 Result 它有
以下API方法和属性可用:
pipe(command[, args[, options]])
将当前命令传输到另一个命令。例如:
x('ls', ['-l'])
.pipe('grep', ['js']);
参数说明如下:
command-要执行的命令(没有任何争论)args-参数数组options- options对象
process
底层的Node.js ChildProcess. Tinyexec保持表面最小化,并且不重新暴露每个child_process方法/事件。使用 proc.process 用于高级访问(流、事件等)。
const proc = x('node', ['./foo.mjs']);
proc.process?.stdout?.on('data', (chunk) => {
// ...
});
proc.process?.once('close', (code) => {
// ...
});
kill([signal])
用指定的信号终止当前进程。默认情况下,这将
使用 SIGTERM 信号。
例如:
const proc = x('ls');
proc.kill();
pid
当前进程ID。例如:
const proc = x('ls');
proc.pid; // number
aborted
进程是否已中止(通过 signal 最初
传入options对象)。
例如:
const proc = x('ls');
proc.aborted; // bool
killed
进程是否已被终止(例如通过 kill() 或者中止
信号)。
例如:
const proc = x('ls');
proc.killed; // bool
exitCode
进程完成执行时收到的退出代码。
例如:
const proc = x('ls');
proc.exitCode; // number (e.g. 1)
与其他库的比较
tinyexec 目的是在Node自己的层之上提供一个轻量级的层
child_process API。
与其他库相比,一些明显的好处是 tinyexec 会轻多少,有多少
占用空间更小,接口更抽象(更“神奇”)。它
还会有同等的安全性和跨平台支持来普及吗
替代方案。
有许多其他库不可能包含的特性 要实现,因为它们会阻止我们提供轻量级层。
例如,如果您喜欢编写脚本而不是单独的命令,那么
更喜欢使用模板,我们强烈推荐
zx. Zx是一个更高级的库
一些相同的工作吗 tinyexec 但是在模板字符串后面吗
接口。
类似地,像 execa 会为各种事情提供帮手吗
比如将文件作为输入传递给进程。我们选择不支持以下功能
这是因为它们中的许多很容易自己完成(使用Node自己的api)。