# bun/no-unportable-commands

> Disallow starting a process with a command that does not work the same on every system

A command that works on macOS and Linux can fail on Windows:

- `npm` is a script there (`npm.cmd`), and you can't start a script without a shell.
- `ls`, `rm` and `grep` don't exist.
- `&&` and `|` are shell syntax, and the shell isn't the same on every system.

The rule checks `exec`, `spawn` and `execFile` from `node:child_process`, their `Sync` versions, `Bun.spawn` and `Bun.spawnSync`, when the command is a string in the call. It also reports any string that contains `ps` with options, such as `"ps -ef"`, because `ps` takes different options on each system.

{/* Generated by src/codegen/lint-rule-docs.ts. Do not edit this section. */}

## Configure

Off by default. To turn it on:

```toml bunfig.toml
[lint.rules]
"bun/no-unportable-commands" = "error" # or "warn"
```

Every option, set to its default. The ones that are commented out are unset by default.

```toml bunfig.toml
[lint.rules]
"bun/no-unportable-commands" = ["error", {
  scripts = ["npm", "npx", "pnpm", "pnpx", "yarn"],
  # posixOnly = <list of strings>,
  launchers = [], # list of strings
}]
```

{/* End of the generated section. */}

## Examples

Reported:

{/* bad {"count": 3} */}
```js
import { exec, spawn } from "node:child_process";

spawn("npm", ["install"]);
spawn("rm", ["-rf", "dist"]);
exec("bun run build && bun run deploy");
```

{/* bad */}
```js
Bun.spawn(["cat", "notes.txt"]);
```

{/* bad */}
```js
const listProcesses = "ps -ef";
```

Not reported:

{/* good */}
```js
import { spawn } from "node:child_process";
import { rm } from "node:fs/promises";

spawn("npm", ["install"], { shell: true });
await rm("dist", { recursive: true, force: true });
```

Bun Shell has its own `rm`, `ls`, `cat`, `&&` and `|`, which work the same on every system:

{/* good */}
```js
import { $ } from "bun";

await $`rm -rf dist`;
await $`bun run build && bun run deploy`;
```

## Options

| Option | Default | What it does |
| --- | --- | --- |
| `scripts` | `["npm", "npx", "pnpm", "pnpx", "yarn"]` | Commands that are `.cmd` scripts on Windows. Reported when they're started without a shell. |
| `posixOnly` | `awk`, `cat`, `chmod`, `cp`, `grep`, `kill`, `ls`, `mv`, `rm`, `sed`, `sh`, `touch` and 21 more | Commands that Windows doesn't have. Reported with or without a shell. |
| `launchers` | `[]` | Names of your own functions that start a process. Their first argument is checked like the first argument of `spawn`. |

Setting a list replaces the default, so repeat the defaults you want to keep.

{/* bad {"options": [{"scripts": ["npm", "tsc"]}]} */}
```js
import { spawnSync } from "node:child_process";

spawnSync("tsc", ["--noEmit"]);
```

{/* bad {"options": [{"launchers": ["run"]}]} */}
```js
await run("grep", ["-r", "TODO", "src"]);
```

## When not to use it

Leave it off if your code never runs on Windows.
