Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Running Processes

Running a child process with proc is as simple as it gets.

Basic Usage

import { run } from "jsr:@j50n/proc@0.23.3";

// Run a command
await run("ls", "-la").lines.collect();

That's it. No boilerplate, no configuration, just run it.

Command and Arguments

The first parameter is the command, the rest are arguments:

run("command", "arg1", "arg2", "arg3")

Important: Arguments are separate parameters, not a single string:

// ✅ Correct
run("ls", "-la", "/home")

// ❌ Wrong - this won't work
run("ls -la /home")

Capturing Output

As an Array

const lines = await run("ls", "-la").lines.collect();
// lines is string[]

Line by Line

for await (const line of run("ls", "-la").lines) {
  console.log(line);
}

First or Last Line

const first = await run("ls").lines.first;
const last = await run("ls").lines.last;

As Raw Bytes

const bytes = await run("cat", "file.bin").collect();
// bytes is Uint8Array[]

Printing to Console

Send output directly to stdout:

await run("ls", "-la").toStdout();

This is perfect for commands where you just want to see the output.

Building Commands Dynamically

Sometimes you need to build a command from variables:

import { type Cmd, run } from "jsr:@j50n/proc@0.23.3";

const cmd: Cmd = ["ls"];

if (showAll) {
  cmd.push("-la");
}

if (directory) {
  cmd.push(directory);
}

await run(...cmd).toStdout();

The Cmd type is an array where the first element is the command (string or URL) and the rest are string arguments. Using the Cmd type ensures type safety when building commands dynamically.

Process Options

Customize process behavior with options:

await run(
  {
    cwd: "/tmp",           // Working directory
    env: { FOO: "bar" },   // Environment variables
  },
  "command",
  "arg1"
).lines.collect();

Working Directory

await run(
  { cwd: "/var/log" },
  "ls"
).toStdout();

Environment Variables

await run(
  { env: { PATH: "/custom/path" } },
  "command"
).lines.collect();

Checking Exit Status

Get the exit status without throwing:

const p = run("command");
await p.lines.collect();  // Consume output first
const status = await p.status;

console.log(`Exit code: ${status.code}`);
console.log(`Success: ${status.success}`);

Remember: Always consume output before checking status, or you'll leak resources.

Process ID

Get the process ID:

const p = run("sleep", "10");
console.log(`PID: ${p.pid}`);
await p.lines.collect();

Running with URLs

You can use URLs for the command:

const scriptUrl = new URL("./script.sh", import.meta.url);
await run(scriptUrl).toStdout();

Common Patterns

Silent Execution

Run a command and ignore output:

await run("command").lines.forEach(() => {});

Capture and Print

Capture output while also printing it:

const lines: string[] = [];
await run("command").lines.forEach(line => {
  console.log(line);
  lines.push(line);
});

Conditional Execution

if (needsProcessing) {
  await run("process-data").toStdout();
}

Error Handling

By default, non-zero exit codes throw ExitCodeError:

try {
  await run("false").lines.collect();
} catch (error) {
  console.error(`Command failed: ${error.code}`);
}

See Error Handling for complete details.

Performance Tips

Stream Instead of Collect

Process data as it arrives rather than loading everything into memory:

// ❌ Loads everything into memory
const lines = await run("cat", "huge-file.txt").lines.collect();
for (const line of lines) {
  process(line);
}

// ✅ Processes one line at a time
for await (const line of run("cat", "huge-file.txt").lines) {
  process(line);
}

Pipe Instead of Collect Intermediate Results

Chain processes instead of collecting intermediate results:

// ❌ Collects intermediate results
const lines1 = await run("cat", "file.txt").lines.collect();
const input = lines1.join("\n");
const lines2 = await run("grep", "pattern").lines.collect();

// ✅ Streams through
await run("cat", "file.txt")
  .run("grep", "pattern")
  .toStdout();

Use take() to Stop Early

Stop processing once you have what you need:

// Stops after finding 10 matches
const first10 = await run("grep", "ERROR", "huge.log")
  .lines
  .take(10)
  .collect();

Filter Before Expensive Operations

Reduce the amount of data flowing through expensive operations:

// ✅ Filter first (fast), then transform (expensive)
const result = await run("cat", "data.txt")
  .lines
  .filter(line => line.length > 0)  // Fast filter
  .map(expensiveTransform)          // Only runs on filtered data
  .collect();

For more performance optimization strategies, see Concurrent Processing and Streaming Large Files.

Next Steps