Command
了解如何在 Effect 中创建、运行和管理命令,包括自定义参数、环境变量以及输入/输出的处理。
@effect/platform/Command 模块提供了一种创建并运行命令的方式,你可以在其中指定进程名以及一个可选的参数列表。
创建命令
Command.make 函数会生成一个命令对象,其中包含进程名、参数以及环境等细节。
示例(为目录列表定义一个命令)
import { Command } from "@effect/platform"
const command = Command.make("ls", "-al")
console.log(command)
/*
{
_id: '@effect/platform/Command',
_tag: 'StandardCommand',
command: 'ls',
args: [ '-al' ],
env: {},
cwd: { _id: 'Option', _tag: 'None' },
shell: false,
gid: { _id: 'Option', _tag: 'None' },
uid: { _id: 'Option', _tag: 'None' }
}
*/
该命令对象在被执行器(executor)运行之前不会真正执行。
运行命令
运行命令需要一个 CommandExecutor,它能够以字符串、行或流等多种格式捕获输出。
示例(运行命令并打印输出)
import { Command } from "@effect/platform"
import { NodeContext, NodeRuntime } from "@effect/platform-node"
import { Effect } from "effect"
const command = Command.make("ls", "-al")
// The program depends on a CommandExecutor
const program = Effect.gen(function* () {
// Runs the command returning the output as a string
const output = yield* Command.string(command)
console.log(output)
})
// Provide the necessary CommandExecutor
NodeRuntime.runMain(program.pipe(Effect.provide(NodeContext.layer)))
输出格式
你可以选择不同的方法来处理命令的输出:
| 方法 | 说明 |
|---|---|
string | 运行命令,并以字符串形式返回输出(使用指定的编码) |
lines | 运行命令,并以行的数组形式返回输出(使用指定的编码) |
stream | 运行命令,并以 Uint8Array 数据块组成的流形式返回输出 |
streamLines | 运行命令,并以行的流形式返回输出(使用指定的编码) |
exitCode
如果你只需要命令的退出码,请使用 Command.exitCode。
示例(获取退出码)
import { Command } from "@effect/platform"
import { NodeContext, NodeRuntime } from "@effect/platform-node"
import { Effect } from "effect"
const command = Command.make("ls", "-al")
const program = Effect.gen(function* () {
const exitCode = yield* Command.exitCode(command)
console.log(exitCode)
})
NodeRuntime.runMain(program.pipe(Effect.provide(NodeContext.layer)))
// Output: 0
自定义环境变量
你可以使用 Command.env 自定义命令的环境变量。当你需要为命令的执行指定特定的变量时,这很有用。
示例(设置环境变量)
在这个例子中,命令在一个 shell 中运行,以确保环境变量被正确处理。
import { Command } from "@effect/platform"
import { NodeContext, NodeRuntime } from "@effect/platform-node"
import { Effect } from "effect"
const command = Command.make("echo", "-n", "$MY_CUSTOM_VAR").pipe(
Command.env({
MY_CUSTOM_VAR: "Hello, this is a custom environment variable!",
}),
// Use shell to interpret variables correctly
// on Windows and Unix-like systems
Command.runInShell(true),
)
const program = Effect.gen(function* () {
const output = yield* Command.string(command)
console.log(output)
})
NodeRuntime.runMain(program.pipe(Effect.provide(NodeContext.layer)))
// Output: Hello, this is a custom environment variable!
向命令提供输入
你可以使用 Command.feed 函数把输入直接发送到命令的标准输入。
示例(将输入发送到命令的标准输入)
import { Command } from "@effect/platform"
import { NodeContext, NodeRuntime } from "@effect/platform-node"
import { Effect } from "effect"
const command = Command.make("cat").pipe(Command.feed("Hello"))
const program = Effect.gen(function* () {
console.log(yield* Command.string(command))
})
NodeRuntime.runMain(program.pipe(Effect.provide(NodeContext.layer)))
// Output: Hello
获取进程详情
你可以访问正在运行的进程的详细信息,例如 exitCode、stdout 和 stderr。
示例(访问正在运行进程的退出码与流)
import { Command } from "@effect/platform"
import { NodeContext, NodeRuntime } from "@effect/platform-node"
import { Effect, Stream, String, pipe } from "effect"
// Helper function to collect stream output as a string
const runString = <E, R>(
stream: Stream.Stream<Uint8Array, E, R>,
): Effect.Effect<string, E, R> =>
stream.pipe(Stream.decodeText(), Stream.runFold(String.empty, String.concat))
const program = Effect.gen(function* () {
const command = Command.make("ls")
const [exitCode, stdout, stderr] = yield* pipe(
// Start running the command and return a handle to the running process
Command.start(command),
Effect.flatMap((process) =>
Effect.all(
[
// Waits for the process to exit and returns
// the ExitCode of the command that was run
process.exitCode,
// The standard output stream of the process
runString(process.stdout),
// The standard error stream of the process
runString(process.stderr),
],
{ concurrency: 3 },
),
),
)
console.log({ exitCode, stdout, stderr })
})
NodeRuntime.runMain(
Effect.scoped(program).pipe(Effect.provide(NodeContext.layer)),
)
将 stdout 流式传输到 process.stdout
要把命令的 stdout 直接流式传输到 process.stdout,可以采用下面的做法:
示例(将命令输出直接流式传输到标准输出)
import { Command } from "@effect/platform"
import { NodeContext, NodeRuntime } from "@effect/platform-node"
import { Effect } from "effect"
// Create a command to run `cat` on a file and inherit stdout
const program = Command.make("cat", "./some-file.txt").pipe(
Command.stdout("inherit"), // Stream stdout to process.stdout
Command.exitCode, // Get the exit code
)
NodeRuntime.runMain(program.pipe(Effect.provide(NodeContext.layer)))