Zx logo zx

#!/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

npm install zx

Documentation

Read documentation on google.github.io/zx.

License

Apache-2.0

Disclaimer: This is not an officially supported Google product.

google/zx

{
"props": {
"initialPayload": {
"allShortcutsEnabled": false,
"path": "/",
"repo": {
"id": 364474335,
"defaultBranch": "main",
"name": "zx",
"ownerLogin": "google",
"currentUserCanPush": false,
"isFork": false,
"isEmpty": false,
"createdAt": "2021-05-05T05:50:01.000Z",
"ownerAvatar": "https://avatars.githubusercontent.com/u/1342004?v=4",
"public": true,
"private": false,
"isOrgOwned": true
},
"currentUser": null,
"refInfo": {
"name": "main",
"listCacheKey": "v0:1732826145.0",
"canEdit": false,
"refType": "branch",
"currentOid": "0705aa1d1651c3b84a014fb7f64d08fe7a6ae0ee"
},
"tree": {
"items": [
{
"name": ".github",
"path": ".github",
"contentType": "directory"
},
{
"name": "docs",
"path": "docs",
"contentType": "directory"
},
{
"name": "examples",
"path": "examples",
"contentType": "directory"
},
{
"name": "man",
"path": "man",
"contentType": "directory"
},
{
"name": "scripts",
"path": "scripts",
"contentType": "directory"
},
{
"name": "src",
"path": "src",
"contentType": "directory"
},
{
"name": "test-d",
"path": "test-d",
"contentType": "directory"
},
{
"name": "test",
"path": "test",
"contentType": "directory"
},
{
"name": ".gitattributes",
"path": ".gitattributes",
"contentType": "file"
},
{
"name": ".gitignore",
"path": ".gitignore",
"contentType": "file"
},
{
"name": ".nycrc",
"path": ".nycrc",
"contentType": "file"
},
{
"name": ".prettierignore",
"path": ".prettierignore",
"contentType": "file"
},
{
"name": ".size-limit.json",
"path": ".size-limit.json",
"contentType": "file"
},
{
"name": "LICENSE",
"path": "LICENSE",
"contentType": "file"
},
{
"name": "README.md",
"path": "README.md",
"contentType": "file"
},
{
"name": "package-lock.json",
"path": "package-lock.json",
"contentType": "file"
},
{
"name": "package.json",
"path": "package.json",
"contentType": "file"
},
{
"name": "tsconfig.json",
"path": "tsconfig.json",
"contentType": "file"
},
{
"name": "tsconfig.prod.json",
"path": "tsconfig.prod.json",
"contentType": "file"
}
],
"templateDirectorySuggestionUrl": null,
"readme": null,
"totalCount": 19,
"showBranchInfobar": false
},
"fileTree": null,
"fileTreeProcessingTime": null,
"foldersToFetch": [],
"treeExpanded": false,
"symbolsExpanded": false,
"isOverview": true,
"overview": {
"banners": {
"shouldRecommendReadme": false,
"isPersonalRepo": false,
"showUseActionBanner": false,
"actionSlug": null,
"actionId": null,
"showProtectBranchBanner": false,
"publishBannersInfo": {
"dismissActionNoticePath": "/settings/dismiss-notice/publish_action_from_repo",
"releasePath": "/google/zx/releases/new?marketplace=true",
"showPublishActionBanner": false
},
"interactionLimitBanner": null,
"showInvitationBanner": false,
"inviterName": null,
"actionsMigrationBannerInfo": {
"releaseTags": [],
"showImmutableActionsMigrationBanner": false,
"initialMigrationStatus": null
}
},
"codeButton": {
"contactPath": "/contact",
"isEnterprise": false,
"local": {
"protocolInfo": {
"httpAvailable": true,
"sshAvailable": null,
"httpUrl": "https://github.com/google/zx.git",
"showCloneWarning": null,
"sshUrl": null,
"sshCertificatesRequired": null,
"sshCertificatesAvailable": null,
"ghCliUrl": "gh repo clone google/zx",
"defaultProtocol": "http",
"newSshKeyUrl": "/settings/ssh/new",
"setProtocolPath": "/users/set_protocol"
},
"platformInfo": {
"cloneUrl": "https://desktop.github.com",
"showVisualStudioCloneButton": false,
"visualStudioCloneUrl": "https://windows.github.com",
"showXcodeCloneButton": false,
"xcodeCloneUrl": "xcode://clone?repo=https%3A%2F%2Fgithub.com%2Fgoogle%2Fzx",
"zipballUrl": "/google/zx/archive/refs/heads/main.zip"
}
},
"newCodespacePath": "/codespaces/new?hide_repo_select=true&repo=364474335"
},
"popovers": {
"rename": null,
"renamedParentRepo": null
},
"commitCount": "665",
"overviewFiles": [
{
"displayName": "README.md",
"repoName": "zx",
"refName": "main",
"path": "README.md",
"preferredFileType": "readme",
"tabName": "README",
"richText": "<article class=\"markdown-body entry-content container-lg\" itemprop=\"text\"><div class=\"markdown-heading\" dir=\"auto\"><h1 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"><a target=\"_blank\" rel=\"noopener noreferrer nofollow\" href=\"https://camo.githubusercontent.com/b960f28465c1404ba7b4c15fdd72ae254efb5182eb25dfda09a5509bd43e5709/68747470733a2f2f676f6f676c652e6769746875622e696f2f7a782f696d672f6c6f676f2e737667\"><img src=\"https://camo.githubusercontent.com/b960f28465c1404ba7b4c15fdd72ae254efb5182eb25dfda09a5509bd43e5709/68747470733a2f2f676f6f676c652e6769746875622e696f2f7a782f696d672f6c6f676f2e737667\" alt=\"Zx logo\" height=\"32\" valign=\"middle\" data-canonical-src=\"https://google.github.io/zx/img/logo.svg\" style=\"max-width: 100%;\"></a> zx</h1><a id=\"user-content--zx\" class=\"anchor\" aria-label=\"Permalink: zx\" href=\"#-zx\"><svg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"><path d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"></path></svg></a></div>\n<div class=\"highlight highlight-source-js notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"#!/usr/bin/env zx\n\nawait $`cat package.json | grep name`\n\nconst branch = await $`git branch --show-current`\nawait $`dep deploy --branch=${branch}`\n\nawait Promise.all([\n $`sleep 1; echo 1`,\n $`sleep 2; echo 2`,\n $`sleep 3; echo 3`,\n])\n\nconst name = 'foo bar'\nawait $`mkdir /tmp/${name}`\"><pre>#!/usr/bin/env zx\n\n<span class=\"pl-k\">await</span> <span class=\"pl-en\">$</span><span class=\"pl-s\">`cat package.json | grep name`</span>\n\n<span class=\"pl-k\">const</span> <span class=\"pl-s1\">branch</span> <span class=\"pl-c1\">=</span> <span class=\"pl-k\">await</span> <span class=\"pl-en\">$</span><span class=\"pl-s\">`git branch --show-current`</span>\n<span class=\"pl-k\">await</span> <span class=\"pl-en\">$</span><span class=\"pl-s\">`dep deploy --branch=<span class=\"pl-s1\"><span class=\"pl-kos\">${</span><span class=\"pl-s1\">branch</span><span class=\"pl-kos\">}</span></span>`</span>\n\n<span class=\"pl-k\">await</span> <span class=\"pl-v\">Promise</span><span class=\"pl-kos\">.</span><span class=\"pl-en\">all</span><span class=\"pl-kos\">(</span><span class=\"pl-kos\">[</span>\n <span class=\"pl-en\">$</span><span class=\"pl-s\">`sleep 1; echo 1`</span><span class=\"pl-kos\">,</span>\n <span class=\"pl-en\">$</span><span class=\"pl-s\">`sleep 2; echo 2`</span><span class=\"pl-kos\">,</span>\n <span class=\"pl-en\">$</span><span class=\"pl-s\">`sleep 3; echo 3`</span><span class=\"pl-kos\">,</span>\n<span class=\"pl-kos\">]</span><span class=\"pl-kos\">)</span>\n\n<span class=\"pl-k\">const</span> <span class=\"pl-s1\">name</span> <span class=\"pl-c1\">=</span> <span class=\"pl-s\">'foo bar'</span>\n<span class=\"pl-k\">await</span> <span class=\"pl-en\">$</span><span class=\"pl-s\">`mkdir /tmp/<span class=\"pl-s1\"><span class=\"pl-kos\">${</span><span class=\"pl-s1\">name</span><span class=\"pl-kos\">}</span></span>`</span></pre></div>\n<p dir=\"auto\">Bash is great, but when it comes to writing more complex scripts,\nmany people prefer a more convenient programming language.\nJavaScript is a perfect choice, but the Node.js standard library\nrequires additional hassle before using. The <code>zx</code> package provides\nuseful wrappers around <code>child_process</code>, escapes arguments and\ngives sensible defaults.</p>\n<div class=\"markdown-heading\" dir=\"auto\"><h2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\">Install</h2><a id=\"user-content-install\" class=\"anchor\" aria-label=\"Permalink: Install\" href=\"#install\"><svg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"><path d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"></path></svg></a></div>\n<div class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"npm install zx\"><pre>npm install zx</pre></div>\n<div class=\"markdown-heading\" dir=\"auto\"><h2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\">Documentation</h2><a id=\"user-content-documentation\" class=\"anchor\" aria-label=\"Permalink: Documentation\" href=\"#documentation\"><svg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"><path d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"></path></svg></a></div>\n<p dir=\"auto\">Read documentation on <a href=\"https://google.github.io/zx/\" rel=\"nofollow\">google.github.io/zx</a>.</p>\n<div class=\"markdown-heading\" dir=\"auto\"><h2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\">License</h2><a id=\"user-content-license\" class=\"anchor\" aria-label=\"Permalink: License\" href=\"#license\"><svg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"><path d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"></path></svg></a></div>\n<p dir=\"auto\"><a href=\"/google/zx/blob/main/LICENSE\">Apache-2.0</a></p>\n<p dir=\"auto\">Disclaimer: <em>This is not an officially supported Google product.</em></p>\n</article>",
"loaded": true,
"timedOut": false,
"errorMessage": null,
"headerInfo": {
"toc": [
{
"level": 1,
"text": " zx",
"anchor": "-zx",
"htmlText": " zx"
},
{
"level": 2,
"text": "Install",
"anchor": "install",
"htmlText": "Install"
},
{
"level": 2,
"text": "Documentation",
"anchor": "documentation",
"htmlText": "Documentation"
},
{
"level": 2,
"text": "License",
"anchor": "license",
"htmlText": "License"
}
],
"siteNavLoginPath": "/login?return_to=https%3A%2F%2Fgithub.com%2Fgoogle%2Fzx"
}
},
{
"displayName": "code-of-conduct.md",
"repoName": "zx",
"refName": "main",
"path": "docs/code-of-conduct.md",
"preferredFileType": "code_of_conduct",
"tabName": "Code of conduct",
"richText": null,
"loaded": false,
"timedOut": false,
"errorMessage": null,
"headerInfo": {
"toc": null,
"siteNavLoginPath": "/login?return_to=https%3A%2F%2Fgithub.com%2Fgoogle%2Fzx"
}
},
{
"displayName": "LICENSE",
"repoName": "zx",
"refName": "main",
"path": "LICENSE",
"preferredFileType": "license",
"tabName": "Apache-2.0",
"richText": null,
"loaded": false,
"timedOut": false,
"errorMessage": null,
"headerInfo": {
"toc": null,
"siteNavLoginPath": "/login?return_to=https%3A%2F%2Fgithub.com%2Fgoogle%2Fzx"
}
},
{
"displayName": "SECURITY.md",
"repoName": ".github",
"refName": "master",
"path": "SECURITY.md",
"preferredFileType": "security",
"tabName": "Security",
"richText": null,
"loaded": false,
"timedOut": false,
"errorMessage": null,
"headerInfo": {
"toc": null,
"siteNavLoginPath": "/login?return_to=https%3A%2F%2Fgithub.com%2Fgoogle%2Fzx"
}
}
],
"overviewFilesProcessingTime": 0
}
},
"appPayload": {
"helpUrl": "https://docs.github.com",
"findFileWorkerPath": "/assets-cdn/worker/find-file-worker-9f8a877aa99f.js",
"findInFileWorkerPath": "/assets-cdn/worker/find-in-file-worker-eb3d353f90ce.js",
"githubDevUrl": null,
"enabled_features": {
"code_nav_ui_events": false,
"overview_shared_code_dropdown_button": false,
"react_blob_overlay": false,
"copilot_conversational_ux_embedding_update": false,
"copilot_smell_icebreaker_ux": true,
"copilot_workspace": false,
"accessible_code_button": true,
"github_models_prompt_link": false
}
}
}
}
{
"accept-ranges": "bytes",
"cache-control": "max-age=0, private, must-revalidate",
"content-encoding": "gzip",
"content-security-policy": "default-src 'none'; base-uri 'self'; child-src github.com/assets-cdn/worker/ github.com/webpack/ github.com/assets/ gist.github.com/assets-cdn/worker/; connect-src 'self' uploads.github.com www.githubstatus.com collector.github.com raw.githubusercontent.com api.github.com github-cloud.s3.amazonaws.com github-production-repository-file-5c1aeb.s3.amazonaws.com github-production-upload-manifest-file-7fdce7.s3.amazonaws.com github-production-user-asset-6210df.s3.amazonaws.com *.rel.tunnels.api.visualstudio.com wss://*.rel.tunnels.api.visualstudio.com objects-origin.githubusercontent.com copilot-proxy.githubusercontent.com proxy.individual.githubcopilot.com proxy.business.githubcopilot.com proxy.enterprise.githubcopilot.com *.actions.githubusercontent.com wss://*.actions.githubusercontent.com productionresultssa0.blob.core.windows.net/ productionresultssa1.blob.core.windows.net/ productionresultssa2.blob.core.windows.net/ productionresultssa3.blob.core.windows.net/ productionresultssa4.blob.core.windows.net/ productionresultssa5.blob.core.windows.net/ productionresultssa6.blob.core.windows.net/ productionresultssa7.blob.core.windows.net/ productionresultssa8.blob.core.windows.net/ productionresultssa9.blob.core.windows.net/ productionresultssa10.blob.core.windows.net/ productionresultssa11.blob.core.windows.net/ productionresultssa12.blob.core.windows.net/ productionresultssa13.blob.core.windows.net/ productionresultssa14.blob.core.windows.net/ productionresultssa15.blob.core.windows.net/ productionresultssa16.blob.core.windows.net/ productionresultssa17.blob.core.windows.net/ productionresultssa18.blob.core.windows.net/ productionresultssa19.blob.core.windows.net/ github-production-repository-image-32fea6.s3.amazonaws.com github-production-release-asset-2e65be.s3.amazonaws.com insights.github.com wss://alive.github.com api.githubcopilot.com api.individual.githubcopilot.com api.business.githubcopilot.com api.enterprise.githubcopilot.com; font-src github.githubassets.com; form-action 'self' github.com gist.github.com copilot-workspace.githubnext.com objects-origin.githubusercontent.com; frame-ancestors 'none'; frame-src viewscreen.githubusercontent.com notebooks.githubusercontent.com; img-src 'self' data: blob: github.githubassets.com media.githubusercontent.com camo.githubusercontent.com identicons.github.com avatars.githubusercontent.com private-avatars.githubusercontent.com github-cloud.s3.amazonaws.com objects.githubusercontent.com secured-user-images.githubusercontent.com/ user-images.githubusercontent.com/ private-user-images.githubusercontent.com opengraph.githubassets.com github-production-user-asset-6210df.s3.amazonaws.com customer-stories-feed.github.com spotlights-feed.github.com objects-origin.githubusercontent.com *.githubusercontent.com; manifest-src 'self'; media-src github.com user-images.githubusercontent.com/ secured-user-images.githubusercontent.com/ private-user-images.githubusercontent.com github-production-user-asset-6210df.s3.amazonaws.com gist.github.com; script-src github.githubassets.com; style-src 'unsafe-inline' github.githubassets.com; upgrade-insecure-requests; worker-src github.com/assets-cdn/worker/ github.com/webpack/ github.com/assets/ gist.github.com/assets-cdn/worker/",
"content-type": "text/html; charset=utf-8",
"date": "Sun, 08 Dec 2024 22:33:25 GMT",
"etag": "08cafa2d55b7f71b67724b7587bb6497",
"referrer-policy": "no-referrer-when-downgrade",
"server": "GitHub.com",
"set-cookie": "logged_in=no; Path=/; Domain=github.com; Expires=Mon, 08 Dec 2025 22:33:25 GMT; HttpOnly; Secure; SameSite=Lax",
"strict-transport-security": "max-age=31536000; includeSubdomains; preload",
"transfer-encoding": "chunked",
"vary": "X-PJAX, X-PJAX-Container, Turbo-Visit, Turbo-Frame, Accept-Encoding, Accept, X-Requested-With",
"x-content-type-options": "nosniff",
"x-frame-options": "deny",
"x-github-request-id": "B98C:26B0DF:A19F9B8:D228215:67561EB5",
"x-xss-protection": "0"
}