## File: README.md

<h1> zx</h1>

```js
#!/usr/bin/env zx

await $`cat package.json | grep name`

const branch = await $`git branch --show-current`
await $`dep deploy --branch=${branch}`

await Promise.all([
  $`sleep 1; echo 1`,
  $`sleep 2; echo 2`,
  $`sleep 3; echo 3`,
])

const name = 'foo bar'
await $`mkdir /tmp/${name}`
```

Bash is great, but when it comes to writing more complex scripts,
many people prefer a more convenient programming language.
JavaScript is a perfect choice, but the Node.js standard library
requires additional hassle before using. No compromise, take the best of both. The `zx` package provides
useful cross-platform wrappers around `child_process`, escapes arguments and
gives sensible defaults.

## Install

```bash
npm install zx
```
All setup options: [zx/setup](https://google.github.io/zx/setup).
See also [**zx@lite**](https://google.github.io/zx/lite).

## Usage

* [Documentation at google.github.io/zx/](https://google.github.io/zx/)
* [Code examples](https://github.com/google/zx/tree/main/examples)

## Compatibility
* Linux, macOS, or Windows
* JavaScript Runtime:
    * Node.js >= 12.17.0
    * Bun >= 1.0.0
    * Deno 1.x, 2.x
    * GraalVM Node.js
* [Bash or PowerShell](https://google.github.io/zx/shell)
* [Both CJS or ESM](https://google.github.io/zx/setup#hybrid) modules in [JS or TS](https://google.github.io/zx/typescript)


## See also

- [MAML](https://maml.dev) — JSON for config, with comments, multiline strings, unquoted keys, and optional commas.

## License

[Apache-2.0](LICENSE)

Disclaimer: _This is not an officially supported Google product._

---

## File: docs/api.md

# API Reference

## `$.sync`
Zx provides both synchronous and asynchronous command executions, returns [`ProcessOutput`](./process-output) or [`ProcessPromise`](./process-promise) respectively.

```js
const list = await $`ls -la`
const dir = $.sync`pwd`
```

## `$({...})`

`$` object holds the default zx [configuration](./configuration), which is used for all execution. To specify a custom preset use `$` as factory:

```js
const $$ = $({
  verbose: false,
  env: {NODE_ENV: 'production'},
})

const env = await $$`node -e 'console.log(process.env.NODE_ENV)'`
const pwd = $$.sync`pwd`
const hello = $({quiet: true})`echo "Hello!"`
```

Moreover, presets are chainable:

```js
const $1 = $({ nothrow: true })
assert.equal((await $1`exit 1`).exitCode, 1)

const $2 = $1({ sync: true }) // Both {nothrow: true, sync: true} are applied
assert.equal($2`exit 2`.exitCode, 2)

const $3 = $({ sync: true })({ nothrow: true })
assert.equal($3`exit 3`.exitCode, 3)
```

### `$({input})`

The input option passes the specified `stdin` to the command.

```js
const p1 = $({ input: 'foo' })`cat`
const p2 = $({ input: Readable.from('bar') })`cat`
const p3 = $({ input: Buffer.from('baz') })`cat`
const p4 = $({ input: p3 })`cat`
const p5 = $({ input: await p3 })`cat`
```

### `$({signal})`

The signal option makes the process abortable.

```js
const {signal} = new AbortController()
const p = $({ signal })`sleep 9999`

setTimeout(() => signal.abort('reason'), 1000)
```

### `$({timeout})`

The timeout option makes the process autokillable after the specified delay.

```js
const p = $({timeout: '1s'})`sleep 999`
```

### `$({nothrow})`

The `nothrow` option suppresses errors and returns a `ProcessOutput` with details.

```js
const o1 = await $({nothrow: true})`exit 1`
o1.ok       // false
o1.exitCode // 1
o1.message  // exit code: 1 ...

const o2 = await $({nothrow: true, spawn() { throw new Error('BrokenSpawn') }})`echo foo`
o2.ok       // false
o2.exitCode // null
o2.message  // BrokenSpawn ...
```

The full options list:
```ts
interface Options {
  cwd:            string
  ac:             AbortController
  signal:         AbortSignal
  input:          string | Buffer | Readable | ProcessOutput | ProcessPromise
  timeout:        Duration
  timeoutSignal:  NodeJS.Signals
  stdio:          StdioOptions
  verbose:        boolean
  sync:           boolean
  env:            NodeJS.ProcessEnv
  shell:          string | true
  nothrow:        boolean
  prefix:         string
  postfix:        string
  quote:          typeof quote
  quiet:          boolean
  detached:       boolean
  preferLocal:    boolean | string | string[]
  spawn:          typeof spawn
  spawnSync:      typeof spawnSync
  store:          TSpawnStore
  log:            typeof log
  kill:           typeof kill
  killSignal:     NodeJS.Signals
  halt:           boolean
  delimiter:      string | RegExp
}
```
See also [Configuration](./configuration).

## `cd()`

Changes the current working directory.

```js
cd('/tmp')
await $`pwd` // => /tmp
```

Like `echo`, in addition to `string` arguments, `cd` accepts and trims
trailing newlines from `ProcessOutput` enabling common idioms like:

```js
cd(await $`mktemp -d`)
```

> ⚠️ `cd` invokes `process.chdir()` internally, so it does affect the global context. To keep `process.cwd()` in sync with separate `$` calls enable [syncProcessCwd()](#syncprocesscwd) hook.

## `fetch()`

A wrapper around the [node-fetch-native](https://www.npmjs.com/package/node-fetch-native)
package.

```js
const r1 = await fetch('https://example.com')
const json = await r1.json()

const r2 = await fetch('https://example.com', {
  signal: AbortSignal.timeout(5000),
})
```

For some cases, `text()` or `json()` can produce extremely large output that exceeds the string size limit.
Streams are just for that, so we've attached a minor adjustment to the `fetch` API to make it more pipe friendly.

```js
const p1 = fetch('https://example.com').pipe($`cat`)
const p2 = fetch('https://example.com').pipe`cat`
```

## `question()`

A wrapper around the [readline](https://nodejs.org/api/readline.html) API.

```js
const bear = await question('What kind of bear is best? ')
const selected = await question('Select an option:', {
  choices: ['A', 'B', 'C'],
})
```

## `sleep()`

A wrapper around the `setTimeout` function.

```js
await sleep(1000)
```

## `echo()`

A `console.log()` alternative which can take [ProcessOutput](#processoutput).

```js
const branch = await $`git branch --show-current`

echo`Current branch is ${branch}.`
// or
echo('Current branch is', branch)
```

## `stdin()`

Returns the stdin as a string.

```js
const content = JSON.parse(await stdin())
```

## `within()`

Creates a new async context.

```js
await $`pwd` // => /home/path
$.foo = 'bar'

within(async () => {
  $.cwd = '/tmp'
  $.foo = 'baz'

  setTimeout(async () => {
    await $`pwd` // => /tmp
    $.foo // baz
  }, 1000)
})

await $`pwd` // => /home/path
$.foo // still 'bar'
```

```js
await $`node --version` // => v20.2.0

const version = await within(async () => {
  $.prefix += 'export NVM_DIR=$HOME/.nvm; source $NVM_DIR/nvm.sh; nvm use 16;'

  return $`node --version`
})

echo(version) // => v16.20.0
```

## `syncProcessCwd()`

Keeps the `process.cwd()` in sync with the internal `$` current working directory if it is changed via [cd()](#cd).

```ts
import {syncProcessCwd} from 'zx'

syncProcessCwd()
syncProcessCwd(false) // pass false to disable the hook
```

> This feature is disabled by default because of performance overhead.

## `retry()`

Retries a callback for a few times. Will return the first
successful result, or will throw after the specified attempts count.

```js
const p = await retry(10, () => $`curl https://medv.io`)

// With a specified delay between attempts.
const p = await retry(20, '1s', () => $`curl https://medv.io`)

// With an exponential backoff.
const p = await retry(30, expBackoff(), () => $`curl https://medv.io`)
```

## `spinner()`

Starts a simple CLI spinner.

```js
await spinner(() => $`long-running command`)

// With a message.
await spinner('working...', () => $`sleep 99`)
```

And it's disabled for `CI` by default.

## `glob()`

The [globby](https://github.com/sindresorhus/globby) package.

```js
const packages = await glob(['package.json', 'packages/*/package.json'])
const markdowns = glob.sync('*.md') // sync API shortcut
```

## `which()`

The [which](https://github.com/npm/node-which) package.

```js
const node = await which('node')
```

If nothrow option is used, returns null if not found.

```js
const pathOrNull = await which('node', { nothrow: true })
```

## `ps`

The [@webpod/ps](https://github.com/webpod/ps) package to provide a cross-platform way to list processes.

```js
const all = await ps.lookup()
const nodejs = await ps.lookup({ command: 'node' })
const children = await ps.tree({ pid: 123 })
const fulltree = await ps.tree({ pid: 123, recursive: true })
```

## `kill()`

A process killer.

```js
await kill(123)
await kill(123, 'SIGKILL')
```

## `tmpdir()`

Creates a temporary directory.

```js
t1 = tmpdir()       // /os/based/tmp/zx-1ra1iofojgg/
t2 = tmpdir('foo')  // /os/based/tmp/zx-1ra1iofojgg/foo/
```

## `tmpfile()`

Temp file factory.

```js
f1 = tmpfile()         // /os/based/tmp/zx-1ra1iofojgg
f2 = tmpfile('f2.txt')  // /os/based/tmp/zx-1ra1iofojgg/foo.txt
f3 = tmpfile('f3.txt', 'string or buffer')
f4 = tmpfile('f4.sh', 'echo "foo"', 0o744) // executable
```

## `minimist`

The [minimist](https://www.npmjs.com/package/minimist) package.

```js
const argv = minimist(process.argv.slice(2), {})
```

## `argv`

A minimist-parsed version of the `process.argv` as `argv`.

```js
if (argv.someFlag) {
  echo('yes')
}
```

Use minimist options to customize the parsing:

```js
const myCustomArgv = minimist(process.argv.slice(2), {
  boolean: [
    'force',
    'help',
  ],
  alias: {
    h: 'help',
  },
})
```

## `chalk`

The [chalk](https://www.npmjs.com/package/chalk) package.

```js
console.log(chalk.blue('Hello world!'))
```

## `fs`

The [fs-extra](https://www.npmjs.com/package/fs-extra) package.

```js
const {version} = await fs.readJson('./package.json')
```

## `os`

The [os](https://nodejs.org/api/os.html) package.

```js
await $`cd ${os.homedir()} && mkdir example`
```

## `path`

The [path](https://nodejs.org/api/path.html) package.

```js
await $`mkdir ${path.join(basedir, 'output')}`
```

## `YAML`

The [yaml](https://www.npmjs.com/package/yaml) package.

```js
console.log(YAML.parse('foo: bar').foo)
```

## `MAML`

The [maml](https://www.npmjs.com/package/maml) package.

```js
const maml = `{
  project: "MAML"
  tags: [ "minimal", "readable" ]

  # With support for comments
  spec: {
    version: 1
    author: "Anton Medvedev"
  }

  notes: """
This is a raw multiline string.
Keeps formatting as‑is.
"""
}`
console.log(MAML.parse(maml).project) // MAML 
```

## `dotenv`

The [envapi](https://www.npmjs.com/package/envapi) package.  
An API to interact with environment vars in [dotenv](https://www.npmjs.com/package/dotenv) format.

```js
// parse
const raw = 'FOO=BAR\nBAZ=QUX'
const data = dotenv.parse(raw) // {FOO: 'BAR', BAZ: 'QUX'}
await fs.writeFile('.env', raw)

// load
const env = dotenv.load('.env')
await $({ env })`echo $FOO`.stdout // BAR

// config
dotenv.config('.env')
process.env.FOO // BAR
```

## `versions`
Exports versions of the zx dependencies.

```ts
import { versions } from 'zx'

versions.zx     // 8.7.2
versions.chalk  // 5.4.1
```

## `quote()`

Default bash quoting function.

```js
quote("$FOO") // "$'$FOO'"
```

## `quotePowerShell()`

PowerShell specific quoting.

```js
quotePowerShell("$FOO") // "'$FOO'"
```

## `useBash()`

Enables bash preset: sets `$.shell` to `bash` and `$.quote` to `quote`.

```js
useBash()
```

## `usePowerShell()`

Switches to PowerShell. Applies the `quotePowerShell` for quoting.

```js
usePowerShell()
```

## `usePwsh()`

Sets pwsh (PowerShell v7+) as `$.shell` default.

```js
usePwsh()
```

---

## File: docs/cli.md

# CLI Usage

Zx provides a CLI for running scripts. It comes with the package and can be used as `zx` executable (if referenced in package.json `"scripts"`, installed [globally](/setup#install) or added to the `$PATH` somehow).

```sh
zx script.mjs
```

`npx` or `node` inits are valid too.
```sh
npx zx script.mjs
node -r zx/globals script.mjs
node --import zx/globals script.mjs
```

## No extensions

If the script does not have a file extension (like `.git/hooks/pre-commit`), zx
assumes that it is
an [ESM](https://nodejs.org/api/modules.html#modules_module_createrequire_filename)
module unless the `--ext` option is specified.

## Non-standard extension
`zx` internally loads scripts via `import` API, so you can use any extension supported by the runtime (nodejs, deno, bun) or apply a [custom loader](https://nodejs.org/api/cli.html#--experimental-loadermodule).
However, if the script has a non-js-like extension (`/^\.[mc]?[jt]sx?$/`) and the `--ext` is specified, it will be used.

```bash
zx script.zx           # Unknown file extension "\.zx"
zx --ext=mjs script.zx # OK
```

## Markdown
The CLI supports [markdown](/markdown) files and interprets `ts`, `js` and `bash` code blocks as scripts.

```bash
zx docs/markdown.md
```

## Remote scripts

If the argument to the `zx` executable starts with `https://`, the file will be
downloaded and executed.

```bash
zx https://raw.githubusercontent.com/google/zx/refs/heads/main/examples/hello.mjs
```

> [!WARNING]
Make sure you trust the remote source and understand the code before running it.

## Scripts from stdin

The `zx` supports executing scripts from stdin.

```js
zx << 'EOF'
await $`pwd`
EOF
```

## `--eval`

Evaluate the following argument as a script.

```bash
cat package.json | zx --eval 'const v = JSON.parse(await stdin()).version; echo(v)'
```

## `--repl`
Starts zx in [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) mode.

## `--install`

```js
// script.mjs:
import sh from 'tinysh'

sh.say('Hello, world!')
```

Add `--install` flag to the `zx` command to install missing dependencies
automatically.

```bash
zx --install script.mjs
```

You can also specify needed version by adding comment with `@` after
the import.

```js
import sh from 'tinysh' // @^1
```

## `--registry`

By default, `zx` uses `https://registry.npmjs.org` as a registry. Customize if needed.

```bash
zx --registry=https://registry.yarnpkg.com script.mjs
```

## `--quiet`

Suppress any outputs.

## `--verbose`

Enable verbose mode.

## `--shell`

Specify a custom shell binary path. By default, zx refers to `bash`.

```bash
zx --shell=/bin/another/sh script.mjs
```

## `--prefer-local, -l`

Prefer locally installed packages and binaries.

```bash
zx --prefer-local=/external/node_modules/or/nm-root script.mjs
```

## `--prefix & --postfix`

Attach a command to the beginning or the end of every command.

```bash
zx --prefix='echo foo;' --postfix='; echo bar' script.mjs
```

## `--cwd`

Set the current working directory.

```bash
zx --cwd=/foo/bar script.mjs
```

## `--env`
Specify an env file.

```bash
zx --env=/path/to/some.env script.mjs
```

When `cwd` option is specified, it will be used as base path:  
`--cwd='/foo/bar' --env='../.env'` → `/foo/.env`

## `--ext`

Overrides the default script extension (`.mjs`).

## `--version, -v`

Print the current `zx` version.

## `--help, -h`

Print help notes.

## Environment variables
All the previously mentioned options can be set via the corresponding `ZX_`-prefixed environment variables.

```bash
ZX_VERBOSE=true ZX_SHELL='/bin/bash' zx script.mjs
```
    
```yaml
steps:
  - name: Run script
    run: zx script.mjs
    env:
      ZX_VERBOSE: true
      ZX_SHELL: '/bin/bash'
```

## `__filename & __dirname`

In [ESM](https://nodejs.org/api/esm.html) modules, Node.js does not provide
`__filename` and `__dirname` globals. As such globals are really handy in scripts,
zx provides these for use in `.mjs` files (when using the `zx` executable).

## `require()`

In [ESM](https://nodejs.org/api/modules.html#modules_module_createrequire_filename)
modules, the `require()` function is not defined.
The `zx` provides `require()` function, so it can be used with imports in `.mjs`
files (when using `zx` executable).

```js
const {version} = require('./package.json')
```

---

## File: docs/configuration.md

# Configuration

## `$.shell`

Specifies what shell is used. Default is `which bash`.

```js
$.shell = '/usr/bin/bash'
```

Or use a CLI argument: `--shell=/bin/bash`

## `$.spawn`

Specifies a `spawn` api. Defaults to native `child_process.spawn`.

To override a sync API implementation, set `$.spawnSync` correspondingly.

## `$.kill`
Specifies a `kill` function. The default implements _half-graceful shutdown_ via `ps.tree()`. You can override with more sophisticated logic.

```js
import treekill from 'tree-kill'

$.kill = (pid, signal = 'SIGTERM') => {
  return new Promise((resolve, reject) => {
    treekill(pid, signal, (err) => {
      if (err) reject(err)
      else resolve()
    })
  })
}
```

## `$.prefix`

Specifies the command that will be prefixed to all commands run.

Default is `set -euo pipefail;`.

Or use a CLI argument: `--prefix='set -e;'`

## `$.postfix`

Like a `$.prefix`, but for the end of the command.

```js
$.postfix = '; exit $LastExitCode' // for PowerShell compatibility
```

## `$.preferLocal`

Specifies whether to prefer `node_modules/.bin` located binaries over globally system installed ones.

```js
$.preferLocal = true

await $`c8 npm test`
```

You can also specify a directory to search for local binaries:

```js
$.preferLocal = '/some/to/bin'
$.preferLocal = ['/path/to/bin', '/another/path/bin']
```

## `$.quote`

Specifies a function for escaping special characters during
command substitution.

## `$.verbose`

Specifies verbosity. Default is `false`.

In verbose mode, `zx` prints all executed commands alongside with their
outputs.

Or use the CLI argument: `--verbose` to set `true`.

## `$.quiet`

Suppresses all output. Default is `false`.

Via CLI argument: `--quiet` sets `$.quiet = true`.

## `$.env`

Specifies an environment variables map.

Defaults to `process.env`.

## `$.cwd`

Specifies a current working directory of all processes created with the `$`.

The [cd()](#cd) func changes only `process.cwd()` and if no `$.cwd` specified,
all `$` processes use `process.cwd()` by default (same as `spawn` behavior).

## `$.log`

Specifies a [logging function](src/log.ts).

```ts
import {LogEntry, log} from 'zx/core'

$.log = (entry: LogEntry) => {
  switch (entry.kind) {
    case 'cmd':
      // for example, apply custom data masker for cmd printing
      process.stderr.write(masker(entry.cmd))
      break
    default:
      log(entry)
  }
}
```

The log mostly acts like a debugger, so by default it uses `process.error` for output.
Override the `$.log.output` to change the stream.

```ts
$.log.output = process.stdout
```

Define `$.log.formatters` to customize each log entry kind printing:

```ts
$.log.formatters = {
  cmd: (entry: LogEntry) => `CMD: ${entry.cmd}`,
  fetch: (entry: LogEntry) => `FETCH: ${entry.url}`
}
```

## `$.timeout`

Specifies a timeout for the command execution.

```js
$.timeout = '1s'
$.timeoutSignal= 'SIGKILL'

await $`sleep 999`
```

## `$.delimiter`
Specifies a delimiter for splitting command output into lines.
Defaults to `\r?\n` (newline or carriage return + newline).

```js
$.delimiter = /\0/        // null character

await $`find ./ -type f -print0 -maxdepth 1`
```

## `$.defaults`

Holds default configuration values. They will be used if the corresponding
`$` options are not specified.

```ts
$.defaults = {
  cwd:            process.cwd(),
  env:            process.env,
  verbose:        false,
  quiet:          false,
  sync:           false,
  shell:          true,
  prefix:         'set -euo pipefail;',   // for bash
  postfix:        '; exit $LastExitCode', // for powershell
  nothrow:        false,
  stdio:          'pipe', // equivalent to ['pipe', 'pipe', 'pipe']
  detached:       false,
  preferLocal:    false,
  spawn:          childProcess.spawn,
  spawnSync:      childProcess.spawnSync,
  log:            $.log,
  kill:           $.kill,
  killSignal:     'SIGTERM',
  timeoutSignal:  'SIGTERM',
  delimiter:      /\r?\n/,
}
```

---

## File: docs/contribution.md

# Contribution Guide

zx is a fully [open-source project](https://github.com/google/zx), which is developing by the community for the community. 
We welcome contributions of any kind, including but not limited to:
* Bug reports
* Feature requests
* Code contributions
* Documentation improvements
* Discussions

https://google.github.io/zx/contribution

## Community Guidelines

This project follows [Google's Open Source Community Guidelines](https://opensource.google/conduct/).
In short: all contributors are treated with respect and fairness.

## Contributor License Agreement

Contributions to this project must be accompanied by a Contributor License
Agreement. You (or your employer) retain the copyright to your contribution;
this simply gives us permission to use and redistribute your contributions as
part of the project. Head over to <https://cla.developers.google.com/> to see
your current agreements on file or to sign a new one.

You generally only need to submit a CLA once, so if you've already submitted one
(even if it was for a different project), you probably don't need to do it
again.

## How to Contribute
Before proposing changes, look for similar ones in the project's [issues](https://github.com/google/zx/issues) and [pull requests](https://github.com/google/zx/pulls). If you can't decide, create a new [discussion](https://github.com/google/zx/discussions) topic, and we will help you figure it out. Dive also into [architecture notes](/architecture) to observe design concepts. When ready to move on:

* Prepare your development environment.
  * Switch to the recommended version of Node.js
    * Install manually `Node.js >= 22`.
    * Delegate the routine to any version manager, that [supports .node_version config](https://stackoverflow.com/questions/27425852/what-uses-respects-the-node-version-file)
    * Use [Volta](https://volta.sh/), the target version will be set automatically from the `package.json`
  * Bash is essential for running zx scripts. Linux and macOS users usually have it installed by default. Consider using [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/install) or [Git Bash](https://git-scm.com/downloads) if you are on Windows.
* Fork [the repository](https://github.com/google/zx).
* Create a new branch.

* Make your changes.
  * If you are adding a new feature, please include additional tests. The coverage threshold is 98%.
  * Create a [conventional-commits](https://www.conventionalcommits.org/en/v1.0.0/) compliant messages.
* Ensure that everything is working:
  * `npm run fmt` to format your code.
  * `npm run test:coverage` to run the tests.
* Push the changes to your fork.
* Create a pull request.
  * Describe your changes in detail.
  * Reference any related issues if applicable.

## Code Reviews

All submissions, including submissions by project members, require review. We use GitHub pull requests for this purpose. Consult [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more information on using pull requests.

## License

The project is licensed under the [Apache-2.0](https://github.com/google/zx?tab=Apache-2.0-1-ov-file#readme)

---

## File: docs/faq.md

# FAQ

## Passing env variables

```js
process.env.FOO = 'bar'
await $`echo $FOO`
```

## Passing array of values

When passing an array of values as an argument to `$`, items of the array will
be escaped
individually and concatenated via space.

Example:

```js
const files = [...]
await $`tar cz ${files}`
```

## Importing into other scripts

It is possible to make use of `$` and other functions via explicit imports:

```js
#!/usr/bin/env node
import {$} from 'zx'

await $`date`
```

## Attaching a profile

By default `child_process` does not include aliases and bash functions.
But you are still able to do it by hand. Just attach necessary directives
to the `$.prefix`.

```js
$.prefix += 'export NVM_DIR=$HOME/.nvm; source $NVM_DIR/nvm.sh; '
await $`nvm -v`
```

## Using GitHub Actions

The default GitHub Action runner comes with `npx` installed.

```yaml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
#      - uses: actions/setup-node@v4
#        with:
#          node-version: 22

      - name: Build with zx
        env:
          FORCE_COLOR: 3
        run: |
          npx zx <<'EOF'
          await $`...`
          EOF
```

## Verbose and Quiet
zx has internal logger, which captures events if a condition is met:

| Event  | Verbose | Quiet   | Description                  |
|--------|---------|---------|------------------------------|
| stdout | `true`  | `false` | Spawned process stdout       |
| stderr | `any`   | `false` | Process stderr data          |
| cmd    | `true`  | `false` | Command execution            |
| fetch  | `true`  | `false` | Fetch resources by http(s)   |
| cd     | `true`  | `false` | Change directory             |
| retry  | `true`  | `false` | Capture exec error           |
| custom | `true`  | `false` | User-defined event           |

By default, both `$.verbose` and `$.quiet` options are `false`, so only `stderr` events are written. Any output goes to the `process.stderr` stream.

You may control this flow globally or in-place
```js
// Global debug mode on
$.verbose = true
await $`echo hello`

// Suppress the particular command
await $`echo fobar`.quiet()

// Suppress everything
$.quiet = true
await $`echo world`

// Turn on in-place debug
await $`echo foo`.verbose()
```

You can also override the default logger with your own:
```js
// globally
$.log = (entry) => {
  switch (entry.kind) {
    case 'cmd':
      console.log('Command:', entry.cmd)
      break
    default:
      console.warn(entry)
  }
}
// or in-place
$({log: () => {}})`echo hello`
```

## Canary / Beta / RC builds

Impatient early adopters can try the experimental zx versions.
But keep in mind: these builds are ⚠️️__beta__ in every sense.

```bash
npm i zx@dev
npx zx@dev --install --quiet <<< 'import _ from "lodash" /* 4.17.15 */; console.log(_.VERSION)'
```

---

## File: docs/getting-started.md

# Getting Started

## Overview

```js
#!/usr/bin/env zx

await $`cat package.json | grep name`

const branch = await $`git branch --show-current`
await $`dep deploy --branch=${branch}`

await Promise.all([
  $`sleep 1; echo 1`,
  $`sleep 2; echo 2`,
  $`sleep 3; echo 3`,
])

const name = 'foo bar'
await $`mkdir /tmp/${name}`
```

Bash is great, but when it comes to writing more complex scripts,
many people prefer a more convenient programming language.
JavaScript is a perfect choice, but the Node.js standard library
requires additional hassle before using. The `zx` package provides
useful wrappers around `child_process`, escapes arguments and
gives sensible defaults.

## Install

```bash
npm install zx
```
or many [other ways](/setup)

## Usage

Write your scripts in a file with an `.mjs` extension in order to
use `await` at the top level. If you prefer the `.js` extension,
wrap your scripts in something like `void async function () {...}()`. [TypeScript](./typescript.md) is also supported.

Add the following shebang to the beginning of your `zx` scripts:

```bash
#!/usr/bin/env zx
```

Now you will be able to run your script like so:

```bash
chmod +x ./script.mjs
./script.mjs
```

Or via the [CLI](cli.md):

```bash
zx ./script.mjs
```

All functions (`$`, `cd`, `fetch`, etc) are available straight away
without any imports.

Or import globals explicitly (for better autocomplete in VS Code).

```js
import 'zx/globals'
```

### ``$`command` ``

Executes a given command using the `spawn` func
and returns [`ProcessPromise`](process-promise.md). It supports both sync and async modes.

```js
const list = await $`ls -la`
const dir = $.sync`pwd`
```

Everything passed through `${...}` will be automatically escaped and quoted.

```js
const name = 'foo & bar'
await $`mkdir ${name}`
```

**There is no need to add extra quotes.** Read more about it in
[quotes](quotes.md).

You can pass an array of arguments if needed:

```js
const flags = [
  '--oneline',
  '--decorate',
  '--color',
]
await $`git log ${flags}`
```

In async mode, zx awaits any `thenable` in literal before executing the command.
```js
const a1 = $`echo foo`
const a2 = new Promise((resolve) => setTimeout(resolve, 20, ['bar', 'baz']))

await $`echo ${a1} ${a2}` // foo bar baz
```

If the executed program returns a non-zero exit code,
[`ProcessOutput`](#processoutput) will be thrown.

```js
try {
  await $`exit 1`
} catch (p) {
  console.log(`Exit code: ${p.exitCode}`)
  console.log(`Error: ${p.stderr}`)
}
```

### `ProcessOutput`

```ts
class ProcessOutput {
  readonly stdout: string
  readonly stderr: string
  readonly signal: string
  readonly exitCode: number
  // ...
  toString(): string // Combined stdout & stderr.
  valueOf(): string  // Returns .toString().trim()
}
```

The output of the process is captured as-is. Usually, programs print a new
line `\n` at the end.
If `ProcessOutput` is used as an argument to some other `$` process,
**zx** will use stdout and trim the new line.

```js
const date = await $`date`
await $`echo Current date is ${date}.`
```

## License

[Apache-2.0](https://github.com/google/zx/blob/main/LICENSE)

Disclaimer: _This is not an officially supported Google product._

---

## File: docs/index.md

---
# https://vitepress.dev/reference/default-theme-home-page
layout: home
titleTemplate: google/zx

hero:
  name: "zx"
  text: "A tool for writing better scripts"
  image:
    src: /img/logo.svg
    alt: Zx Logo
  actions:
    - theme: brand
      text: Documentation
      link: /getting-started

features:
  - title: Simple
    details: Write your scripts in a familiar language.
  - title: Powerful
    details: Interact with the full ecosystem of JS libraries.
  - title: Batteries included
    details: Everything you need, right out of the box.
---

---

## File: docs/known-issues.md

# Known Issues

## Output gets truncated

This is a known issue with `console.log()` (see [nodejs/node#6379](https://github.com/nodejs/node/issues/6379)).
It's caused by different behaviour of `console.log()` writing to the terminal vs
to a file. If a process calls `process.exit()`, buffered output will be truncated.
To prevent this, the process should use `process.exitCode = 1` and wait for the
process to exit itself. Or use something like [exit](https://www.npmjs.com/package/exit) package.

Workaround is to write to a temp file:
```js
const tmp = await $`mktemp` // Creates a temp file.
const {stdout} = await $`cmd > ${tmp}; cat ${tmp}`
```

## Colors in subprocess

You may see what tools invoked with `await $` don't show colors, compared to
what you see in a terminal. This is because, the subprocess does not think it's
a TTY and the subprocess turns off colors. Usually there is a way force
the subprocess to add colors.

```js
process.env.FORCE_COLOR='1'
await $`cmd`
```

---

## File: docs/markdown.md

# Markdown Scripts

Imagine a script with code blocks, formatted comments, schemas, illustrations, etc. [Markdown](https://en.wikipedia.org/wiki/Markdown) is right for this purpose.
Combine `ts`, `js`, `bash` sections to produce a single zx scenario. For example:

````text
# Some script
`ls` — is an unix command to get directory contents. Let's see how to use it in `zx`:

```js
// ts, js, cjs, mjs, etc
const {stdout} = await $`ls -l`
console.log('directory contents:', stdout)
```

This part invokes the same command in a different way:
```bash
# bash syntax
ls -l
```
````

And how it looks like:

> # Some script
> `ls` — is an unix command to get directory contents. Let's see how to use it in `zx`:
> ```js
> // ts, js, cjs, mjs, etc
> const {stdout} = await $`ls -l`
> console.log('directory contents:', stdout)
> ```
>
> This part invokes the same command in a different way:
> ```bash
> # bash syntax
> ls -l
> ```

The rest is simple: just run via `zx` command:
```bash 
zx script.md
```

## Hints
You can use imports here as well:

```js
await import('chalk')
```

`js`, `javascript`, `ts`, `typescript`, `sh`, `shell`, `bash` code blocks will be executed by zx. 

```bash
VAR=$(date)
echo "$VAR" | wc -c
```

Other kinds are ignored:

```css
body .hero {
  margin: 42px;
}
```

The `__filename` will be pointed to **markdown.md**:

```js
console.log(chalk.yellowBright(__filename))
```