{"id":17526472,"url":"https://github.com/bin-cli/bin-cli","last_synced_at":"2025-03-06T06:30:31.987Z","repository":{"id":154062697,"uuid":"622148894","full_name":"bin-cli/bin-cli","owner":"bin-cli","description":"A simple task/script runner for any programming language","archived":false,"fork":false,"pushed_at":"2024-08-21T19:51:01.000Z","size":745,"stargazers_count":6,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-08-21T21:59:04.411Z","etag":null,"topics":["bash","cli","linux","script-runner","scripting","shell","task-runner"],"latest_commit_sha":null,"homepage":"https://github.com/bin-cli/bin-cli#readme","language":"Gherkin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bin-cli.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-04-01T09:10:05.000Z","updated_at":"2024-08-21T19:44:41.000Z","dependencies_parsed_at":null,"dependency_job_id":"ca158c5f-dee6-4a0e-a621-f7109ee8be3b","html_url":"https://github.com/bin-cli/bin-cli","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bin-cli%2Fbin-cli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bin-cli%2Fbin-cli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bin-cli%2Fbin-cli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bin-cli%2Fbin-cli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bin-cli","download_url":"https://codeload.github.com/bin-cli/bin-cli/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242161183,"owners_count":20081819,"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","cli","linux","script-runner","scripting","shell","task-runner"],"created_at":"2024-10-20T15:01:48.638Z","updated_at":"2025-03-06T06:30:31.974Z","avatar_url":"https://github.com/bin-cli.png","language":"Gherkin","funding_links":[],"categories":["Gherkin"],"sub_categories":[],"readme":"\u003c!--\n\n\n\n\n\n\n\n********************************************************************************\n********************************************************************************\n********************************************************************************\n\n    This file was automatically generated.\n\n    DO NOT EDIT IT DIRECTLY.\n\n    You should edit the source in the features/ directory instead.\n\n    See CONTRIBUTING.md for more details.\n\n********************************************************************************\n********************************************************************************\n********************************************************************************\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n--\u003e\n\n\u003c!-- features/1.00-introduction.md --\u003e\n\n# Bin CLI – A simple task/script runner for any language\n\nBin CLI is a simple task runner, designed to be used in code repositories, with scripts written in any programming language.\n\nIt automatically [searches in parent directories](#how-it-works), so you can run scripts from anywhere in the project tree. It also supports [aliases](#aliases), [unique prefix matching](#unique-prefix-matching) and [tab completion](#tab-completion), reducing the amount you need to type.\n\nIt is implemented as a self-contained Bash script, small enough to bundle with your dotfiles or projects if you want to.  It only requires Bash 3+ and a small number of [coreutils](https://www.gnu.org/software/coreutils/manual/) commands, so it should work on almost any Unix-like system (Linux, macOS, etc.). On Windows, it can be used via [WSL](https://learn.microsoft.com/en-us/windows/wsl/about), [Git Bash](https://gitforwindows.org/), [Cygwin](https://www.cygwin.com/) or [MSYS2](https://www.msys2.org/).\n\nCollaborators / contributors who choose not to install Bin can run the scripts directly, so you can enjoy the benefits without adding a hard dependency or extra barrier to entry.\n\n_To see how Bin compares to some of the alternatives (Just, Task, Make, etc.), see [the wiki](https://github.com/bin-cli/bin-cli/wiki/Alternatives-to-Bin-CLI)._\n\n\u003c!-- features/2.00-how-it-works.feature --\u003e\n\n## How It Works\n\nA project just needs a `bin/` folder and some executable scripts - for example:\n\n```\nrepo/\n├── bin/\n│   ├── build\n│   ├── deploy\n│   └── hello\n└── ...\n```\n\nThe scripts can be written in [any language](https://github.com/bin-cli/bin-cli/wiki/Hello%2C-World),\nor can even be compiled binaries, as long as they are executable (`chmod +x`). Here is a very simple\n`bin/hello` shell script:\n\n```bash\n#!/bin/sh\necho \"Hello, ${1:-World}!\"\n```\n\nTo execute it, run:\n\n```\n$ bin hello\nHello, World!\n```\n\nNow you may be thinking why not just run it directly, like this:\n\n```\n$ bin/hello\n```\n\nAnd that would do the same thing - but Bin will also search in parent directories, so you can use it from anywhere in the project:\n\n```bash\n$ cd app/Http/Controllers/\n$ bin/hello                # Doesn't work :-(\n$ ../../../bin/hello       # Works, but is rather tedious to type :-/\n$ bin hello                # Still works :-)\n```\n\n\u003e [!WARNING]\n\u003e Bin CLI executes arbitrary commands/scripts in the current working directory\n\u003e (or the directory specified by `--dir`) - the same as if you executed them\n\u003e directly. You should not run commands from untrusted sources.\n\n\u003c!-- features/2.01-listing-commands.feature --\u003e\n\n### Listing Commands\n\nIf you run `bin` on its own, it will list all available commands:\n\n\u003cpre\u003e\n$ bin\n\u003cstrong\u003eAvailable Commands\u003c/strong\u003e\nbin build\nbin deploy\nbin hello\n\u003c/pre\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eCan I add descriptions to the commands?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nYes - see [Help text](#help-text), below.\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003c!-- features/2.02-subcommands.feature --\u003e\n\n### Subcommands\n\nIf you have multiple related commands, you may want to group them together and make subcommands. To do that, just create a subdirectory:\n\n```\nrepo/\n└── bin/\n    └── deploy/\n        ├── production\n        └── staging\n```\n\nNow `bin deploy production` will run `bin/deploy/production`, and `bin deploy` will list the available subcommands:\n\n\u003cpre\u003e\n$ bin deploy\n\u003cstrong\u003eAvailable Subcommands\u003c/strong\u003e\nbin deploy production\nbin deploy staging\n\u003c/pre\u003e\n\n\u003c!-- features/2.03-unique-prefix-matching.feature --\u003e\n\n### Unique Prefix Matching\n\nAny unique prefix is enough to run a command - so if `bin/hello` is the only script starting with `h`, all of these will work too:\n\n```bash\n$ bin hell\n$ bin hel\n$ bin he\n$ bin h\n```\n\nThis also works with subcommands - e.g. `bin dep prod` might run `bin/deploy/production`.\n\nIf you type a prefix that isn't unique, Bin will display a list of matches instead:\n\n\u003cpre\u003e\n$ bin hel\n\u003cstrong\u003eMatching Commands\u003c/strong\u003e\nbin hello\nbin help\n\u003c/pre\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eHow can I disable unique prefix matching?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nIf you prefer to disable unique prefix matching, use `--exact` on the command line:\n\n```bash\nbin --exact hello\n```\n\nYou'll probably want to set up a shell alias rather than typing it manually:\n\n```bash\nalias bin='bin --exact'\n```\n\nTo disable it for a project, add this at the top of [`.binconfig`](#config-files):\n\n```ini\nexact = true\n```\n\nTo enable it again, overriding the config file, use `--prefix`:\n\n```bash\nbin --prefix hel\n```\n\nAgain, you'll probably want to set up a shell alias:\n\n```bash\nalias bin='bin --prefix'\n```\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003c!-- features/3.00-installation-ubuntu.md --\u003e\n\n## Installation on Ubuntu\n\nIf you are using Ubuntu, you can install Bin CLI from the [official PPA package](https://launchpad.net/~bin-cli/+archive/ubuntu/bin-cli):\n\n```bash\nsudo add-apt-repository ppa:bin-cli/bin-cli\nsudo apt install bin-cli\n```\n\nThis includes [man pages](https://bin-cli.github.io/bin-cli/bin.1.html) (`man bin`, `man binconfig`) and [tab completion](#tab-completion).\n\nIt will be upgraded automatically when you run `apt update \u0026\u0026 apt upgrade` or equivalent.\n\nTo remove it again:\n\n```bash\nsudo apt remove bin-cli\n```\n\n\u003c!-- features/3.01-installation-debian.md --\u003e\n\n## Installation on Debian\n\nIf you are using Debian, or another Debian-based operating system, you can install Bin CLI by downloading the .deb package:\n\n```bash\ncd /tmp\nwget https://github.com/bin-cli/bin-cli/releases/latest/download/bin-cli.deb\nsudo apt install ./bin-cli.deb\n```\n\nThis includes [man pages](https://bin-cli.github.io/bin-cli/bin.1.html) (`man bin`, `man binconfig`) and [tab completion](#tab-completion).\n\nIt will not be upgraded automatically. If you want to be notified when a new version is released, watch [this repo](https://github.com/bin-cli/bin-cli) (select Watch \u003e Custom \u003e Releases, or Watch \u003e All Activity if you prefer).\n\nTo remove it again:\n\n```bash\nsudo apt remove bin-cli\n```\n\n\u003c!-- features/3.02-installation-redhat.md --\u003e\n\n## Installation on Red Hat\n\nIf you are using Red Hat, or another Red Hat-based operating system, you can install Bin CLI by downloading the .rpm package:\n\n```bash\ncd /tmp\nwget https://github.com/bin-cli/bin-cli/releases/latest/download/bin-cli.rpm\nsudo rpm -iv bin-cli.rpm\n```\n\nThis includes [man pages](https://bin-cli.github.io/bin-cli/bin.1.html) (`man bin`, `man binconfig`) and [tab completion](#tab-completion).\n\nIt will not be upgraded automatically. If you want to be notified when a new version is released, watch [this repo](https://github.com/bin-cli/bin-cli) (select Watch \u003e Custom \u003e Releases, or Watch \u003e All Activity if you prefer).\n\nTo remove it again:\n\n```bash\nsudo rpm -ev bin-cli\n```\n\n\u003c!-- features/4.00-manual-installation.md --\u003e\n\n## Manual Installation\n\nBin CLI is a single script that you can simply [download](https://github.com/bin-cli/bin-cli/releases/latest/download/bin) to anywhere in your `$PATH`.\n\nTo install it system-wide (for all users) in `/usr/local/bin`:\n\n```bash\nsudo wget https://github.com/bin-cli/bin-cli/releases/latest/download/bin -O /usr/local/bin/bin\nsudo chmod +x /usr/local/bin/bin\n```\n\nTo install it for the current user only in `$HOME/.local/bin`:\n\n```bash\nmkdir -p ~/.local/bin\nwget https://github.com/bin-cli/bin-cli/releases/latest/download/bin -O ~/.local/bin/bin\nchmod +x ~/.local/bin/bin\n\n# If $HOME/.local/bin is not already in your $PATH:\necho 'PATH=\"$HOME/.local/bin:$PATH\"' \u003e\u003e ~/.profile\nPATH=\"$HOME/.local/bin:$PATH\"\n```\n\nTo remove it again, just delete the file:\n\n```bash\nsudo rm /usr/local/bin/bin\n```\n\nOr:\n\n```bash\nrm ~/.local/bin/bin\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cem\u003eWhat are the system requirements?\u003c/em\u003e\u003c/summary\u003e\n\n\u003e The requirements are minimal:\n\u003e\n\u003e - Bash 3.x or above\n\u003e - [Core Utilities](https://www.gnu.org/software/coreutils/coreutils.html), [BusyBox](https://busybox.net/) or equivalent\n\u003e   (specifically `basename`, `chmod`, `dirname`, `mkdir`, `readlink`, `sort`, `tr`, `uniq`)\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cem\u003eWhat if \u003ccode\u003ewget\u003c/code\u003e is not available?\u003c/em\u003e\u003c/summary\u003e\n\n\u003e You can use `curl` instead:\n\u003e\n\u003e ```bash\n\u003e sudo curl https://github.com/bin-cli/bin-cli/releases/latest/download/bin -Lo /usr/local/bin/bin\n\u003e curl https://github.com/bin-cli/bin-cli/releases/latest/download/bin -Lo ~/.local/bin/bin\n\u003e ```\n\u003e\n\u003e At least one of `curl` or `wget` are usually installed, or can easily be\n\u003e installed, so that covers 99.99% of cases... But just for completeness - you\n\u003e can also use any other HTTP client - e.g. [HTTPie](https://httpie.io/docs/cli):\n\u003e\n\u003e ```bash\n\u003e sudo http get https://github.com/bin-cli/bin-cli/releases/latest/download/bin -do /usr/local/bin/bin\n\u003e http get https://github.com/bin-cli/bin-cli/releases/latest/download/bin -do ~/.local/bin/bin\n\u003e ```\n\u003e\n\u003e Or [Node.js](https://docs.npmjs.com/cli/commands/npx):\n\u003e\n\u003e ```bash\n\u003e sudo npx download-cli https://github.com/bin-cli/bin-cli/releases/latest/download/bin -o /usr/local/bin/\n\u003e npx download-cli https://github.com/bin-cli/bin-cli/releases/latest/download/bin -o ~/.local/bin/\n\u003e ```\n\u003e\n\u003e Or just click [this link](https://github.com/bin-cli/bin-cli/releases/latest/download/bin)\n\u003e to download it using your browser.\n\n\u003c/details\u003e\n\n\u003c!-- features/4.01-tab-completion.feature --\u003e\n\n### Tab Completion\n\nTo enable tab completion in Bash, add this:\n\n```bash\ncommand -v bin \u0026\u003e/dev/null \u0026\u0026 eval \"$(bin --completion)\"\n```\n\nTo any of the following files:\n\n- `/usr/share/bash-completion/completions/bin` (recommended for system-wide installs)\n- `/etc/bash_completion.d/bin`\n- `~/.local/share/bash-completion/completions/bin` (recommended for per-user installs)\n- `~/.bash_completion`\n- `~/.bashrc`\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eHow to use tab completion with custom aliases?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nIf you are using a simple [shell alias](#aliasing-the-bin-command), e.g. `alias b=bin`, update the filename to match and add `--exe \u003cname\u003e`:\n\n```bash\n# e.g. in /usr/share/bash-completion/completions/b\ncommand -v bin \u0026\u003e/dev/null \u0026\u0026 eval \"$(bin --completion --exe b)\"\n```\n\nIf you have globally disabled [unique prefix matching](#unique-prefix-matching), e.g. `alias bin='bin --exact'`, add the same parameter here:\n\n```bash\n# e.g. in /usr/share/bash-completion/completions/bin\ncommand -v bin \u0026\u003e/dev/null \u0026\u0026 eval \"$(bin --completion --exact)\"\n```\n\nSimilarly, if you are using an alias with a [custom script directory](#custom-script-directory), e.g. `alias scr='bin --dir scripts'`, add the same parameter here:\n\n```bash\n# e.g. in /usr/share/bash-completion/completions/scr\ncommand -v bin \u0026\u003e/dev/null \u0026\u0026 eval \"$(bin --completion --exe scr --dir scripts)\"\n```\n\nIf you have multiple aliases, just create a file for each one (or put them all together in `~/.bash_completion` or `~/.bashrc`).\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eWhy use \u003ccode\u003eeval\u003c/code\u003e?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nUsing `eval` makes it more future-proof - in case I need to change how tab completion works in the future.\n\nIf you prefer, you can manually run `bin --completion` and paste the output into the file instead.\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eWhat about other shells (Zsh, Fish, etc)?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nOnly Bash is supported at this time. I will add other shells if there is [demand for it](https://github.com/bin-cli/bin-cli/issues/12), or gladly accept [pull requests](https://github.com/bin-cli/bin-cli/pulls).\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003c!-- features/4.02-man-pages.md --\u003e\n\n### Man Pages\n\nTo download the [man pages](https://bin-cli.github.io/bin-cli/bin.1.html) system-wide:\n\n```bash\nsudo mkdir -p /usr/local/share/man/man{1,5}\nsudo wget https://github.com/bin-cli/bin-cli/releases/latest/download/bin.1.gz -O /usr/local/share/man/man1/bin.1.gz\nsudo wget https://github.com/bin-cli/bin-cli/releases/latest/download/binconfig.5.gz -O /usr/local/share/man/man5/binconfig.5.gz\n```\n\nOr for the current user:\n\n```bash\nmkdir -p ~/.local/share/man/man{1,5}\nwget https://github.com/bin-cli/bin-cli/releases/latest/download/bin.1.gz -O ~/.local/share/man/man1/bin.1.gz\nwget https://github.com/bin-cli/bin-cli/releases/latest/download/binconfig.5.gz -O ~/.local/share/man/man5/binconfig.5.gz\n\n# If $HOME/.local/share/man is not already in your $MANPATH:\necho 'MANPATH=\"$HOME/.local/share/man:$MANPATH\"' \u003e\u003e ~/.profile\nMANPATH=\"$HOME/.local/share/man:$MANPATH\"\n```\n\n\u003c!-- features/4.03-upgrading.md --\u003e\n\n### Upgrading\n\nTo upgrade to the latest version at any time, just repeat the same `wget` command(s) as above. If you want to be notified when a new version is released, watch [this repo](https://github.com/bin-cli/bin-cli) (select Watch \u003e Custom \u003e Releases, or Watch \u003e All Activity if you prefer).\n\n\u003c!-- features/5.00-per-project-setup.md --\u003e\n\n## Per-Project Setup\n\nIn the root of the repository, create a `bin/` directory. For example:\n\n```bash\nmkdir bin\n```\n\nThen create some scripts inside it, in the language of your choice, using the text editor of your choice:\n\n```bash\nnano bin/sample\n```\n\nAnd make them executable:\n\n```bash\nchmod +x bin/*\n```\n\nThat's all there is to it. Now you can run them:\n\n```bash\nbin sample\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cem\u003eCan I change the directory name?\u003c/em\u003e\u003c/summary\u003e\n\n\u003e Yes - see [custom script directory](#custom-script-directory), below.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cem\u003eDoes the \u003ccode\u003ebin/\u003c/code\u003e directory have to exist?\u003c/em\u003e\u003c/summary\u003e\n\n\u003e No - if you define all commands [inline in the config file](#inline-commands), you can omit the `bin/` directory.\n\u003e\n\u003e You can also put the scripts [in the root directory](#custom-script-directory) - but then [subcommands](#subcommands) won't be supported.\n\n\u003c/details\u003e\n\n\u003c!-- features/5.01-config-files.feature --\u003e\n\n### Config Files\n\nSome of the features below require you to create a config file. It should be named `.binconfig` and placed in the project root directory, alongside the `bin/` directory:\n\n```\nrepo/\n├── bin/\n│   └── ...\n└── .binconfig\n```\n\nConfig files are written in [INI format](https://en.wikipedia.org/wiki/INI_file). Here is an example:\n\n```ini\n; Global settings\ndir = scripts\nexact = true\nmerge = true\ntemplate = #!/bin/sh\\n\\n\n\n; Settings for each command (script)\n[hello]\nalias = hi\nargs = [name]\nhelp = Say \"Hello, World!\"\n\n[phpunit]\ncommand = \"$BIN_ROOT/vendor/bin/phpunit\" \"%@\"\n```\n\nThe supported global keys are:\n\n- `dir` (string) - Sets a [custom script directory](#custom-script-directory)\n- `exact` (boolean) - Disables [unique prefix matching](#unique-prefix-matching)\n- `merge` (boolean, or the string `optional`) - Enables [directory merging](#merging-directories)\n- `template` (string) - Sets the template for [scripts created with `--create`](#creating--editing-scripts)\n\nThe supported per-command keys are:\n\n- `alias`/`aliases` (comma-separated strings) - [Aliases](#aliases)\n- `args` (string) - [List of arguments](#help-text)\n- `help` (string) - [Help text](#help-text)\n- `command` (string) - [Inline commands](#inline-commands)\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eDo I need to create a \u003ccode\u003e.binconfig\u003c/code\u003e file?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nNo - `.binconfig` only needs to exist if you want to use the features described below.\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eWhat dialect of INI file is used?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nThe INI file is parsed according to the following rules:\n\n- Spaces are allowed around the `=` signs, and are automatically trimmed from the start/end of lines.\n- Values should not be quoted - quotes will be treated as part of the value. This avoids the need to escape inner quotes.\n- Boolean values can be set to `true`/`false` (recommended), `yes`/`no`, `on`/`off` or `1`/`0` (all case-insensitive). Anything else triggers an error.\n- Lines that start with `;` or `#` are comments, which are ignored. No other lines can contain comments.\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eWhy isn\u0026#39;t \u003ccode\u003e.binconfig\u003c/code\u003e inside \u003ccode\u003ebin/\u003c/code\u003e?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\n`.binconfig` can't be inside the `bin/` directory because the [`dir` setting](#custom-script-directory) may change the name of the `bin/` directory, creating a chicken-and-egg problem (how would we find it in the first place?).\n\nTechnically it would be possible to support both locations for every setting _except_ `dir` - and I may if there is demand for it... But then we would have to decide what happens if there are two files - error, or merge them? If merged, how should we handle conflicts? Which one should `bin --edit .binconfig` open? And so on.\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eWhat happens if an invalid key name is used?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nInvalid keys are ignored, to allow for forwards-compatibility with future versions of Bin CLI which may support additional settings. (The downside of this is you won't be warned if you make a typo, so I may change this in the future.)\n\nInvalid command names are displayed as a warning when you run `bin`, after the command listing.\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003c!-- features/6.00-other-features.md --\u003e\n\n## Other Features\n\n\u003c!-- features/6.01-creating-edit-scripts.feature --\u003e\n\n### Creating / Editing Scripts\n\nYou can use these commands to more easily create/edit scripts in your preferred editor (`$VISUAL` or `$EDITOR`, with `editor`, `nano` or `vi` as fallbacks):\n\n```bash\nbin --create sample\nbin --edit sample\n```\n\nThe `--create` (`-c`) command will pre-fill the file with a typical Bash script template and make it executable.\n\nThe `--edit` (`-e`) command supports [unique prefix matching](#unique-prefix-matching) (e.g. `bin -e sam`).\n\nYou can also use `bin --create .binconfig` to create a [config file](#config-files), and `bin --edit .binconfig` to edit it.\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eHow can I customise the template for new scripts?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nAdd this to the top of [`.binconfig`](#config-files):\n\n```ini\ntemplate = #!/usr/bin/env bash\\nset -euo pipefail\\n\\n\n```\n\nIt is passed to `echo -e`, so you can use escape sequences such as `\\n` for new lines.\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003c!-- features/6.02-help-text.feature --\u003e\n\n### Help Text\n\nTo add a short (one-line) description of each command, enter it in `.binconfig` as follows:\n\n```ini\n[deploy]\nhelp = Sync the code to the live server\n```\n\nThis will be displayed when you run `bin` with no parameters (or with an ambiguous prefix). For example:\n\n\u003cpre\u003e\n$ bin\n\u003cstrong\u003eAvailable Commands\u003c/strong\u003e\nbin artisan    Run Laravel Artisan with the appropriate version of PHP\nbin deploy     Sync the code to the live server\nbin php        Run the appropriate version of PHP for this project\n\u003c/pre\u003e\n\nI recommend keeping the descriptions short. The scripts could then support a `--help` parameter, or similar, if further explanation is required.\n\nFor subcommands, use the full command name, not the filename:\n\n```ini\n[deploy live]\nhelp = Deploy to the production site\n\n[deploy staging]\nhelp = Deploy to the staging site\n```\n\nYou can also list the arguments that each command accepts:\n\n```ini\n[test]\nargs = [suite]\nhelp = Run the given test suite, or all test suites\n```\n\nI recommended keeping this short - one or two arguments - and writing `[...]` if there are many arguments available. For example:\n\n\u003cpre\u003e\n$ bin\n\u003cstrong\u003eAvailable Commands\u003c/strong\u003e\nbin artisan [...]    Run Laravel Artisan with the appropriate version of PHP\nbin deploy           Sync the code to the live server\nbin test [suite]     Run the given test suite, or all test suites\n\u003c/pre\u003e\n\n\u003c!-- features/6.03-aliases.feature --\u003e\n\n### Aliases\n\nYou can define aliases in `.binconfig` like this:\n\n```ini\n[deploy]\nalias = publish\n```\n\nThis means `bin publish` is an alias for `bin deploy`, and running either would execute the `bin/deploy` script.\n\nYou can define multiple aliases by separating them with commas (and optional spaces). You can use the key `aliases` if you prefer to be pedantic:\n\n```ini\n[deploy]\naliases = publish, push\n```\n\nOr you can list them on separate lines instead:\n\n```ini\n[deploy]\nalias = publish\nalias = push\n```\n\nAlternatively, you can use symlinks to define aliases:\n\n```bash\n$ cd bin\n$ ln -s deploy publish\n```\n\nBe sure to use relative targets, not absolute ones, so they work in any location. (Absolute targets will be rejected, for safety.)\n\nIn any case, aliases are listed alongside the help text when you run `bin` with no parameters (or with a non-unique prefix). For example:\n\n\u003cpre\u003e\n$ bin\n\u003cstrong\u003eAvailable Commands\u003c/strong\u003e\nbin artisan    Run Laravel Artisan with the appropriate version of PHP \u003cem\u003e(alias: art)\u003c/em\u003e\nbin deploy     Sync the code to the live server \u003cem\u003e(aliases: publish, push)\u003c/em\u003e\n\u003c/pre\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eCan I define aliases for commands that have subcommands?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nYes - for example, given a script `bin/deploy/live` and this config file:\n\n```ini\n[deploy]\nalias = push\n```\n\n`bin push live` would be an alias for `bin deploy live`, and so on.\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eHow do aliases affect unique prefix matching?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nAliases are checked when looking for unique prefixes. In this example:\n\n```ini\n[deploy]\naliases = publish, push\n```\n\n- `bin pub` would match `bin publish`, which is an alias for `bin deploy`, which runs the `bin/deploy` script\n- `bin pu` would match both `bin publish` and `bin push` - but since both are aliases for `bin deploy`, that would be treated as a unique prefix and would therefore also run `bin/deploy`\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eWhat happens if an alias conflicts with another command?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nDefining an alias that conflicts with a script or another alias will cause Bin to exit with error code 246 and print a message to stderr.\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003c!-- features/6.04-inline-commands.feature --\u003e\n\n### Inline Commands\n\nIf you have a really short script, you can instead write it as an inline command in `.binconfig`:\n\n```ini\n[hello]\ncommand = echo \"Hello, ${1:-World}!\"\n\n[phpunit]\ncommand = \"$BIN_ROOT/vendor/bin/phpunit\" \"$@\"\n\n[watch]\ncommand = \"$BIN_DIR/build\" --watch \"$@\"\n```\n\nThe following variables are available:\n\n- `$1`, `$2`, ... and `$@` contain the additional arguments, as normal\n- `$BIN_ROOT` points to the project root directory (where `.binconfig` is found)\n- `$BIN_DIR` points to the directory containing the scripts (usually `$BIN_ROOT/bin`, unless configured otherwise)\n- The [standard environment variables](#environment-variables-to-use-in-scripts) listed below\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eHow complex can the command be?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nThe command is executed within a Bash shell (`bash -c \"$command\"`), so it may contain logic operators\n(`\u0026\u0026`, `||`), multiple commands separated by `;`, and pretty much anything else that you can fit into\na single line. Multi-line commands are not supported.\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eWhy is this not the standard / recommended way to write commands?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nIf you're using Bin as a replacement for the one-line tasks typically [defined in package.json](https://docs.npmjs.com/cli/commands/npm-run-script), it might seem perfectly natural to write all tasks this way (and you can do that if you want to).\n\nHowever, I generally recommend writing slightly longer, more robust scripts. For example, checking that dependencies are installed before you attempt to do something that requires them, or even [installing them automatically](https://github.com/bin-cli/bin-cli/wiki/Automatically-installing-dependencies). It's hard to do that when you're limited to a single line of code.\n\nIt also violates this fundamental principle of Bin, listed in the introduction above:\n\n\u003e Collaborators / contributors who choose not to install Bin can run the scripts directly, so you can enjoy the benefits without adding a hard dependency or extra barrier to entry.\n\nThat's why I recommend only using inline commands for very simple commands, such as calling a third-party script installed by a package manager (as in the `phpunit` example) or creating a shorthand for a command that could easily be run directly (as in the `watch` example).\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003c!-- features/6.05-script-extensions.feature --\u003e\n\n### Script Extensions\n\nYou can create scripts with an extension to represent the language, if you prefer that:\n\n```\nrepo/\n└── bin/\n    ├── sample1.sh\n    ├── sample2.py\n    └── sample3.rb\n```\n\nThe extensions will be removed when [listing commands](#listing-commands) and in [tab completion](#tab-completion) (as long as there are no conflicts):\n\n\u003cpre\u003e\n$ bin\n\u003cstrong\u003eAvailable Commands\u003c/strong\u003e\nbin sample1\nbin sample2\nbin sample3\n\u003c/pre\u003e\n\nYou can run them with or without the extension:\n\n```bash\n$ bin sample1\n$ bin sample1.sh\n```\n\nYou must include the extension in `.binconfig`:\n\n```ini\n[sample1.sh]\nhelp = The extension is required here\n```\n\n\u003c!-- features/6.06-custom-script-directory.feature --\u003e\n\n### Custom Script Directory\n\nIf you prefer the directory to be named `scripts` (or something else), you can configure that at the top of `.binconfig`:\n\n```ini\ndir = scripts\n```\n\nThe path is relative to the `.binconfig` file - it won't search any parent or child directories.\n\nThis option is provided for use in projects that already have a `scripts` directory or similar. I recommend renaming the directory to `bin` if you can, for consistency with the executable name and [standard UNIX naming conventions](https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard).\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eCan I put the scripts in the project root directory?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nIf you have your scripts directly in the project root, you can use this:\n\n```ini\ndir = .\n```\n\nHowever, subcommands will **not** be supported, because that would require searching the whole (potentially [very large](https://i.redd.it/tfugj4n3l6ez.png)) directory tree to find all the scripts.\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eWhat if I can\u0026#39;t create a config file?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nYou can also set the script directory at the command line:\n\n```bash\n$ bin --dir scripts\n```\n\nBin will search the parent directories as normal, but ignore any `.binconfig` files it finds. This is mostly useful to support repositories you don't control.\n\nYou will probably want to define an alias:\n\n```bash\nalias scr='bin --exe scr --dir scripts'\n```\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eCan I use an absolute path?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nNot in a `.binconfig` file, but you can use an absolute path at the command line. For example, you could put your all generic development tools in `~/.local/bin/dev/` and run them as `dev \u003cscript\u003e`:\n\n```bash\nalias dev=\"bin --exe dev --dir $HOME/.local/bin/dev\"\n```\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003c!-- features/6.07-automatic-shims.feature --\u003e\n\n### Automatic Shims\n\nI often use Bin to create shims for other executables - for example, [different PHP versions](https://github.com/bin-cli/bin-cli/wiki/PHP-Version-Shim) or [running scripts inside Docker](https://github.com/bin-cli/bin-cli/wiki/Docker-Exec-Shim).\n\nRather than typing `bin php` every time, I use a Bash alias to run it automatically:\n\n```bash\nalias php='bin php'\n```\n\nHowever, that only works when inside a project directory. The `--shim` parameter tells Bin to run the global command of the same name if no local script is found:\n\n```bash\nalias php='bin --shim php'\n```\n\nNow typing `php -v` will run `bin/php -v` if available, but fall back to a regular `php -v` if not.\n\nIf you want to run a fallback command that is different to the script name, use `--fallback \u003ccommand\u003e` instead:\n\n```bash\nalias php='bin --fallback php8.1 php'\n```\n\nBoth of these options imply `--exact` - i.e. [unique prefix matching](#unique-prefix-matching) is disabled (otherwise it might call `bin/phpunit`, for example).\n\n\u003c!-- features/6.08-environment-variables.feature --\u003e\n\n### Environment Variables To Use in Scripts\n\nBin will set the environment variable `$BIN_COMMAND` to the command that was executed, for use in help messages:\n\n```bash\necho \"Usage: ${BIN_COMMAND-$0} [...]\"\n```\n\nFor example, if you ran `bin sample -h`, it would be set to `bin sample`, so would output:\n\n```\nUsage: bin sample [...]\n```\n\nBut if you ran the script manually with `bin/sample -h`, it would output the fallback from `$0` instead:\n\n```\nUsage: bin/sample [...]\n```\n\nThere is also `$BIN_EXE`, which is set to the name of the executable (typically just `bin`, but that [may be overridden](#aliasing-the-bin-command)).\n\n\u003c!-- features/6.09-aliasing-the-bin-command.feature --\u003e\n\n### Aliasing the `bin` Command\n\nIf you prefer to shorten the script prefix from `bin` to `b`, for example, you can create an alias in your shell's config. For example, in `~/.bashrc`:\n\n```bash\nalias b='bin --exe b'\n```\n\nThe `--exe` parameter is used to override the executable name used in the [environment variables](#environment-variables-to-use-in-scripts) (`$BIN_COMMAND`, `$BIN_EXE`) and the [list of commands](#listing-commands):\n\n\u003cpre\u003e\n$ b\n\u003cstrong\u003eAvailable Commands\u003c/strong\u003e\nb hello\n\u003c/pre\u003e\n\nYou can skip it (i.e. use `alias b='bin'`) if you prefer it to say `bin`.\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eAlternatively, you can use a symlink\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nSystem-wide installation:\n\n```bash\n$ sudo ln -s bin /usr/local/bin/b\n```\n\nPer-user installation:\n\n```bash\n$ ln -s bin ~/.local/bin/b\n```\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003c!-- features/6.10-merging-directories.feature --\u003e\n\n### Merging Directories\n\nOccasionally, you may want to define commands that are specific to a certain subdirectory, without losing access to the main (parent) project commands.\n\nFor example, you may have several different themes, each with its own `build` command:\n\n```\nrepo/                  ← parent project\n├── bin/\n│   └── deploy\n└── themes/\n    └── one/           ← child project\n        ├── bin/\n        │   └── build\n        └── .binconfig\n```\n\nNormally, if you are in the `themes/one/` directory:\n\n- `bin build` runs `themes/one/bin/build`\n- `bin deploy` gives an error, because the parent directory is ignored\n\nBut if you add this to [`.binconfig`](#config-files) (in the child project):\n\n```ini\nmerge = true\n```\n\nThen the two `bin/` directories are merged, so:\n\n- `bin build` still runs `themes/one/bin/build`\n- `bin deploy` runs `bin/deploy`\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eCan child project commands override parent project commands?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nNo - any conflicts will be reported as an error, the same as if they were defined at the same level (e.g. by defining a command and an alias with the same name).\n\nThis is mostly because it would make the conflict-checking code too complex - but it has the benefit of enforcing simplicity (parent commands work from anywhere, and accidental conflicts are reported).\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eDoes this work with inline commands and aliases?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nYes - you can use any combination of scripts, inline commands and aliases in both the parent and child projects.\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eWhat if no parent project is found?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nIf you set `merge = true` but there is no parent `bin/` directory (or `.binconfig` file), Bin will exit with an error.\n\nTo avoid that, set `merge = optional` instead. This may be useful in subprojects that have separate repositories, so you can't guarantee they will be cloned together.\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cem\u003eCan three (or more) directories be merged?\u003c/em\u003e\u003c/summary\u003e\u003cblockquote\u003e\n\nYes - just set `merge = true` at each level below the first.\n\n\u003c/blockquote\u003e\u003c/details\u003e\n\n\u003c!-- features/6.11-automatic-exclusions.feature --\u003e\n\n### Automatic Exclusions\n\nScripts starting with `_` (underscore) are excluded from listings, but can still be executed. This can be used for hidden tools and helper scripts that are not intended to be executed directly. (Or you could use a separate [`libexec` directory](https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch04s07.html) in the project root if you prefer.)\n\nFiles starting with `.` (dot / period) are always ignored and cannot be executed with Bin.\n\nFiles that are not executable (not `chmod +x`) are listed as warnings in the command listing, and will error if you try to run them. The exception is when using `dir = .`, where they are just ignored.\n\nA number of common non-executable file types (`*.json`, `*.md`, `*.txt`, `*.yaml`, `*.yml`) are also excluded when using `dir = .`, even if they are executable, to reduce the noise when all files are executable (e.g. on FAT32 filesystems).\n\nThe directories `/bin`, `/snap/bin`, `/usr/bin`, `/usr/local/bin`, `$HOME/bin` and `$HOME/.local/bin` are ignored when searching parent directories, unless there is a corresponding `.binconfig` file, because they are common locations for global executables (typically in `$PATH`).\n\n\u003c!-- features/7.00-cli-reference.md --\u003e\n\n## CLI Reference\n\n\u003c!-- START auto-update-cli-reference --\u003e\n\n```\nUsage: bin [OPTIONS] [--] [COMMAND] [ARGUMENTS...]\n\nOptions that can be used with a command:\n  --dir DIR             Specify the directory name to search for (overrides .binconfig)\n  --exact               Disable unique prefix matching\n  --exe NAME            Override the executable name displayed in the command list\n  --fallback COMMAND    If the command is not found, run the given global command (implies '--exact')\n  --prefix              Enable unique prefix matching (overrides .binconfig)\n  --shim                If the command is not found, run the global command with the same name (implies '--exact')\n\nOptions that do something with a COMMAND:\n  --create, -c          Create the given script and open in your $EDITOR (implies '--exact')\n  --edit, -e            Open the given script in your $EDITOR\n\nOptions that do something special and don't accept a COMMAND:\n  --completion          Output a tab completion script for the current shell\n  --info                Display information about the current project (root, bin directory and config file location)\n  --help, -h            Display this help\n  --version, -v         Display the current version number\n\nAny options must be given before the command, because everything after the command will be passed as parameters to the script.\n\nFor more details see https://github.com/bin-cli/bin-cli/tree/main#readme\n```\n\n\u003c!-- END auto-update-cli-reference --\u003e\n\n\u003c!-- features/7.01-cli-arguments.feature --\u003e\n\n\u003c!-- features/8.00-license.md --\u003e\n\n## License\n\n[MIT License](LICENSE.md)\n\n\u003c!-- features/9.98-edge-cases.feature --\u003e\n\n\u003c!-- features/9.99-code-quality.feature --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbin-cli%2Fbin-cli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbin-cli%2Fbin-cli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbin-cli%2Fbin-cli/lists"}