{"id":17954373,"url":"https://github.com/txthinking/jb","last_synced_at":"2025-03-25T00:32:03.186Z","repository":{"id":172586340,"uuid":"649449577","full_name":"txthinking/jb","owner":"txthinking","description":"jb: write script in an easier way than bash","archived":true,"fork":false,"pushed_at":"2023-12-04T05:34:07.000Z","size":122857,"stargazers_count":21,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-02T09:03:59.681Z","etag":null,"topics":["bash","bun","cli","javascript","nodejs","shell"],"latest_commit_sha":null,"homepage":"https://www.txthinking.com","language":"Zig","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/txthinking.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-06-04T21:47:39.000Z","updated_at":"2025-01-20T08:59:13.000Z","dependencies_parsed_at":"2024-02-05T22:12:10.683Z","dependency_job_id":null,"html_url":"https://github.com/txthinking/jb","commit_stats":null,"previous_names":["txthinking/jb"],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/txthinking%2Fjb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/txthinking%2Fjb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/txthinking%2Fjb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/txthinking%2Fjb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/txthinking","download_url":"https://codeload.github.com/txthinking/jb/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245377921,"owners_count":20605374,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bash","bun","cli","javascript","nodejs","shell"],"created_at":"2024-10-29T10:14:40.031Z","updated_at":"2025-03-25T00:31:58.173Z","avatar_url":"https://github.com/txthinking.png","language":"Zig","readme":"# `jb` = `javascript` + `bash`\n\n```\n#!/usr/bin/env jb\n\n$`ls -l`\n\nvar output = $1`whoami`\n$(`echo ${output}`)\n```\n\nBash is great, but when it comes to writing more complex scripts, many people prefer a more convenient programming language. JavaScript is a perfect choice. The jb provides useful wrappers. The jb is a [bun](https://github.com/oven-sh/bun) port of [zx](https://github.com/google/zx), the advantage is that you don't need to install node, and **jb is just a standalone binary**.\n\n## Install\n\njb is just a standalone binary, so you can [download](https://github.com/txthinking/jb/releases) and put it in your PATH. Or install it via [nami](https://github.com/txthinking/nami)\n\n```\nnami install jb\n```\n\n## Documentation\n\nJust write your scripts in a file with an `.js`\n\nAdd the following shebang to the beginning of your `jb` scripts:\n\n```bash\n#!/usr/bin/env jb\n```\n\nNow you will be able to run your script like so:\n\n```bash\nchmod +x ./script.js\n./script.js\n```\n\nOr via the `jb` executable:\n\n```bash\njb ./script.js\n```\n\nOr executes remote script\n\n```bash\njb https://www.txthinking.com/script.js\n```\n\nAll functions (`$`, `cd`, `fetch`, etc) are available straight away without any imports.\n\n### ``$`command` ``\n\nExecutes a given command, keep the default behavior of stdout and stderr like bash\n\n```js\n$`ls -l`\n```\n\nOr put a variable in command\n\n```js\nvar name = 'hello'\n$(`mkdir ${name}`)\n```\n\nYou can pass an array of arguments if needed:\n\n```js\nvar flags = [\n  '-l',\n  '-h',\n]\n$(`ls ${flags.join(' ')}`)\n```\n\nIf the executed program failed, error will be thrown.\n\n```js\n$`brook unknownsubcommand`\n```\n\n### ``$1`command` ``\n\nSame as ``$`command` ``, but will return stdout and trim space, as you know, 1 is STDOUT\n\n```js\nvar count = $1`ls -l | wc -l`\n$(`echo ${count}`)\n```\n\n### `env()`\n\nSet env\n\n```js\nenv('HELLO', \"JB\")\n$`echo $HELLO` // =\u003e JB\n```\n\n### `cd()`\n\nChanges the current working directory.\n\n```js\ncd('/tmp')\n$`pwd` // =\u003e /tmp\n```\n\n### `question()`\n\n```js\nvar name = question('What is your name? ')\n```\n\n### `confirm()`\n\n```js\nvar ok = confirm('Do you really want to leave?');\n```\n\n### `sleep()`\n\n```js\nsleep(1000)\n```\n\n### `now()`\n\nCurrent unix timestamp\n\n```js\nvar t = now()\n```\n\n### `echo()`\n\nA `console.log()` alternative\n\n```js\necho('hello')\n```\n\n### `which()`\n\nFile path or null\n\n```js\nvar bin = which('brook')\n```\n\n### `exit()`\n\nExit the script\n\n```js\nexit()\n```\n\n### `exists_file()`\n\nfile exists or not\n\n```js\nvar yn = exists_file('path/to/file.txt')\n```\n\n### `read_file()`\n\nRead the text from local file\n\n```js\nvar str = read_file('path/to/file.txt')\n```\n\n### `write_file()`\n\nWrite text to local file\n\n```js\nwrite_file('path/to/file.txt', 'some text')\n```\n\n### `append_file()`\n\nAppend text to local file\n\n```js\nappend_file('path/to/file.txt', 'some text')\n```\n\n### `cp()`\n\nCopy file or http file from zip/tar.gz/tar.xz to local\n\n```js\ncp('https://github.com/txthinking/brook/releases/latest/download/brook_darwin_arm64', '/tmp/brook');\n```\n\nCopy file from zip\n```\n7z l ~/Downloads/bun-darwin-aarch64.zip\n```\n```\n   Date      Time    Attr         Size   Compressed  Name\n------------------- ----- ------------ ------------  ------------------------\n2023-06-03 15:54:41 D....            0            0  bun-darwin-aarch64\n2023-06-03 15:54:41 .....     46584592     16787941  bun-darwin-aarch64/bun\n------------------- ----- ------------ ------------  ------------------------\n2023-06-03 15:54:41           46584592     16787941  1 files, 1 folders\n```\n\n```js\ncp('$HOME/Downloads/bun-darwin-aarch64.zip', 'bun-darwin-aarch64/bun', '/tmp/bun');\n```\n\nCopy multiple files from tar.gz\n```\ntar ztf ~/Downloads/cowsay_2.0.4_macOS_arm64.tar.gz\n```\n```\nLICENSE\ndoc/cowsay.1\ncowsay\ncowthink\n```\n```js\ncp('$HOME/Downloads/cowsay_2.0.4_macOS_arm64.tar.gz', {\n    'cowsay': '/tmp/cowsay',\n    'cowthink': '/tmp/cowthink',\n});\n```\nCopy multiple files from tar.xz\n```\ntar Jtf ~/Downloads/shadowsocks-v1.15.3.aarch64-apple-darwin.tar.xz\n```\n```\nsslocal\nssserver\nssurl\nssmanager\nssservice\n```\n```js\ncp('https://github.com/shadowsocks/shadowsocks-rust/releases/latest/download/shadowsocks-v1.15.3.aarch64-apple-darwin.tar.xz', {\n    'sslocal': '/tmp/sslocal',\n    'ssserver': '/tmp/ssserver',\n});\n```\n\n## Async Functions\n\n### `stdin()`\n\nReturns the stdin as a string.\n\n```js\nvar s = await stdin()\necho(`got ${s} from pipe`);\n```\n```\necho hello | jb ./script.js\n```\n\n### `retry()`\n\nWill return after the first successful attempt, or will throw after specifies attempts count.\n\n```js\nvar s = await retry(() =\u003e $1`curl https://www.txthinking.com`)\n\n// delay 1s\nvar s = await retry(() =\u003e $1`curl https://www.txthinking.com`, 1000)\n\n// delay 1s and max 3 times\nvar s = await retry(() =\u003e $1`curl https://www.txthinking.com`, 1000, 3)\n```\n\n## Web, Node, Bun\n\n### built-in [Web API](https://developer.mozilla.org/en-US/docs/Web/API) such as [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)\n\n```js\nvar res = await fetch('https://www.txthinking.com');\n```\n\n### built-in [node](https://nodejs.org/api/)\n\n```js\nimport os from 'node:os';\n\necho(os.homedir());\n```\n\n### built-in [bun](https://bun.sh/docs/api/http)\n\n```js\nBun.serve({\n    port: 8080,\n    hostname: '127.0.0.1',\n    fetch(req) {\n        return new Response(\"jb!\");\n    },\n});\n```\n\n## Executing commands on remote hosts\n\nThe `jb` uses [sshexec](https://github.com/txthinking/sshexec) to execute commands on remote hosts.\n\n```js\n$`sshexec -s 1.2.3.4:22 -u user -p pass -c 'ls -l'`\n```\nDownload file from remote\n\n```js\n$`sshexec -s 1.2.3.4:22 -u user -p pass --download /server/path/to/file --to /local/path/to/file`\n```\nUpload file to remote\n\n```js\n$`sshexec -s 1.2.3.4:22 -u user -k path/to/private/key --upload /local/path/to/file --to /server/path/to/file`\n```\n\n## License\n\njb itself is [MIT-licensed](LICENSE). Refer to the [dependencies license](https://bun.sh/docs/project/licensing) for information.\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftxthinking%2Fjb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftxthinking%2Fjb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftxthinking%2Fjb/lists"}