> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/zhcndoc/bun/llms.txt
> Use this file to discover all available pages before exploring further.

# Shell Scripting

> Write shell scripts in JavaScript with Bun's cross-platform shell

Bun includes a built-in, cross-platform shell that you can use directly in JavaScript and TypeScript files. It uses the `$` template literal for running shell commands.

## Basic Usage

```ts theme={null}
import { $ } from "bun";

// Run a command
await $("echo Hello World");

// Capture output
const output = await $("ls -la").text();
console.log(output);

// Check exit code
const result = await $("git status");
if (result.exitCode === 0) {
  console.log("Git working directory is clean");
}
```

## Template Interpolation

### Safe Variable Substitution

Variables are automatically escaped:

```ts theme={null}
const filename = "my file.txt";

// Variables are safely quoted
await $("cat ${filename}");
// Executes: cat "my file.txt"

const dir = "/home/user";
const pattern = "*.js";
await $("ls ${dir}/${pattern}");
```

### Raw Strings

Use `.raw` to pass values without escaping:

```ts theme={null}
const flags = "-la";
await $("ls ${flags.raw}");

// For complex expressions
const sorting = process.env.REVERSE ? "-r" : "";
await $("ls ${sorting.raw} -t");
```

## Piping and Redirection

### Pipes

Connect commands with pipes:

```ts theme={null}
await $("cat file.txt | grep pattern | sort | uniq");

// Multi-line for readability
await $(`
  cat access.log |
  grep ERROR |
  wc -l
`);
```

### Input/Output Redirection

```ts theme={null}
// Write to file
await $("echo Hello > output.txt");

// Append to file
await $("echo World >> output.txt");

// Read from file
await $("wc -l < input.txt");

// Redirect stderr
await $("command 2> errors.log");

// Redirect both stdout and stderr
await $("command > output.log 2>&1");
```

### Here Documents

```ts theme={null}
await $(`
  cat << EOF > config.txt
  line 1
  line 2
  line 3
  EOF
`);
```

## Control Flow

### Conditional Execution

```ts theme={null}
// AND - run second command only if first succeeds
await $("mkdir temp && cd temp && touch file.txt");

// OR - run second command only if first fails
await $("test -f config.json || cp default.json config.json");
```

### Command Grouping

```ts theme={null}
// Sequential commands
await $("cd src; pwd; ls");

// Background jobs
await $("npm run dev &");
```

## Working with Output

### Text Output

```ts theme={null}
const text = await $("cat file.txt").text();
console.log(text);
```

### JSON Output

```ts theme={null}
const data = await $("curl https://api.example.com/data").json();
console.log(data);
```

### Binary Data

```ts theme={null}
const buffer = await $("cat image.png").arrayBuffer();
```

### Line-by-Line

```ts theme={null}
const lines = await $("cat file.txt").lines();
for (const line of lines) {
  console.log(line);
}
```

### Streaming

```ts theme={null}
const proc = $("tail -f /var/log/system.log");

for await (const chunk of proc.stdout) {
  console.log(new TextDecoder().decode(chunk));
}
```

## Error Handling

### Checking Exit Codes

```ts theme={null}
const result = await $("git pull");

if (result.exitCode !== 0) {
  console.error("Git pull failed:", result.stderr.toString());
  process.exit(1);
}
```

### Exceptions

By default, commands don't throw on non-zero exit:

```ts theme={null}
// Check manually
const result = await $("false");
console.log(result.exitCode); // 1

// Or use .quiet() to suppress stderr
const result = await $("command-that-might-fail").quiet();
```

### Try/Catch

```ts theme={null}
try {
  await $("risky-command");
} catch (err) {
  if (err.exitCode) {
    console.error(`Command failed with code ${err.exitCode}`);
  }
}
```

## Environment Variables

### Setting Variables

```ts theme={null}
// For a single command
await $("NODE_ENV=production npm run build");

// Using .env()
const result = await $("node script.js").env({
  NODE_ENV: "production",
  API_KEY: process.env.API_KEY,
});
```

### Accessing Variables

```ts theme={null}
const home = await $("echo $HOME").text();
console.log(home.trim());
```

## Options

### Change Directory

```ts theme={null}
await $("ls").cwd("/tmp");

// Or inline
await $("cd /tmp && ls");
```

### Quiet Mode

Suppress stderr output:

```ts theme={null}
const result = await $("command").quiet();
```

### Nothrow

Prevent throwing on errors:

```ts theme={null}
const result = await $("might-fail").nothrow();
if (!result.success) {
  console.log("Command failed but we handled it");
}
```

## Built-in Commands

Bun's shell includes cross-platform implementations of common commands:

* `cd` - Change directory
* `echo` - Print text
* `ls` - List files
* `cat` - Concatenate files
* `rm` - Remove files
* `mkdir` - Create directories
* `mv` - Move files
* `cp` - Copy files
* `pwd` - Print working directory
* `which` - Locate commands
* `exit` - Exit with code

These work identically on Windows, macOS, and Linux.

## Advanced Features

### Glob Patterns

```ts theme={null}
// Match multiple files
await $("cat src/**/*.ts | wc -l");

// Brace expansion
await $("touch file{1,2,3}.txt");
```

### Command Substitution

```ts theme={null}
const count = await $("ls | wc -l").text();
await $("echo There are ${count} files");
```

### Process Substitution

```ts theme={null}
// Compare outputs
await $("diff <(ls dir1) <(ls dir2)");
```

## Running Scripts

### Inline Scripts

```ts theme={null}
import { $ } from "bun";

await $(`
  echo "Starting build..."
  rm -rf dist
  mkdir -p dist
  bun build src/index.ts --outdir dist
  echo "Build complete!"
`);
```

### Script Files

Create executable shell scripts with Bun:

```ts theme={null}
#!/usr/bin/env bun
import { $ } from "bun";

const branch = await $("git branch --show-current").text();
console.log(`Current branch: ${branch.trim()}`);

if (branch.includes("main")) {
  console.log("Deploying to production...");
  await $("npm run deploy:prod");
} else {
  console.log("Deploying to staging...");
  await $("npm run deploy:staging");
}
```

Make it executable:

```bash theme={null}
chmod +x deploy.ts
./deploy.ts
```

## Performance

Bun's shell is optimized for:

* **Fast startup** - No subprocess overhead for built-in commands
* **Memory efficiency** - Streams data instead of buffering
* **Concurrent execution** - Multiple commands run in parallel where possible

## Differences from Bash

### Not a Full Shell

Bun's shell supports common scripting patterns but is not POSIX-compliant:

* No functions or aliases
* Limited job control
* Simplified parameter expansion

### Web Standards

Bun uses Web APIs:

* `ReadableStream` instead of Unix pipes
* `TextDecoder` for encoding
* `fetch()` for HTTP

## Comparison with Other Tools

### vs. Node.js child\_process

```ts theme={null}
// Bun Shell - concise
await $("ls | grep .ts | wc -l");

// Node - verbose
const { spawn } = require('child_process');
const ls = spawn('ls');
const grep = spawn('grep', ['.ts']);
const wc = spawn('wc', ['-l']);
ls.stdout.pipe(grep.stdin);
grep.stdout.pipe(wc.stdin);
```

### vs. Zx (Google)

Bun's shell is similar to `zx` but:

* Built-in (no extra dependency)
* Faster (no subprocess for simple commands)
* Cross-platform (works on Windows natively)

## Best Practices

1. **Use template literals for readability**
   ```ts theme={null}
   await $(`
     npm install &&
     npm run build &&
     npm test
   `);
   ```

2. **Check exit codes for critical commands**
   ```ts theme={null}
   const result = await $("npm test");
   if (result.exitCode !== 0) process.exit(1);
   ```

3. **Stream large outputs**
   ```ts theme={null}
   for await (const line of $("tail -f log.txt").lines()) {
     console.log(line);
   }
   ```

4. **Use quiet mode for noisy commands**
   ```ts theme={null}
   await $("npm install").quiet();
   ```
