KO
|
EN
gitlite β search
Search
#javascript
#python
#hacktoberfest
#react
#ai
#typescript
#llm
#go
#golang
#android
#machine-learning
#rust
#deep-learning
#linux
sub
β 24
Open GitHub β
Shell scripts with superpowers π¦ΈββοΈ
Download README (.md)
Explore Similar Repositories
android-msdk
:
This library allows you to embed payment acceptance using "Click" into Android mobile applications. For the library to function properly, the user must be connected to Click Merchant using the Shop API scheme
XtPlayer
:
ζ―ζεΌΉεΉγεεΉηHTML5 ζζΎε¨(dev)
UC-Berkeley-CS-294-Deep-RL
:
Implementation of Deep RL Algorithms for UC Berkeley's CS 294-112 (Fall 2018): Deep Reinforcement Learning
mud
:
ε€ιγγ£γΉγγγγγγΌγΉγ¨γγιηεδ»γι’ζ°εγγγ°γ©γγ³γ°θ¨θͺ
tanks
:
2D game written in C++ & Qt for Windows, Linux and Android
// repository documentation
Was this content helpful?
β 0
(0 ratings)
Select Rating:
β
β
β
β
β
Submit Feedback
Recent Feedback
×
Download README
Do you want to download the
README.md
file for
sub
?
Download (.md)
# Sub     Scripts with superpowers. `sub` is a tool for organizing scripts into a unified command-line interface. It allows the dynamic creation of a CLI from a directory (and subdirectories) of scripts with support for documentation, argument validation, and completions. ## Table of Contents <!-- vim-markdown-toc GFM --> * [Key features](#key-features) * [Demo](#demo) * [Installation](#installation) * [Setup](#setup) * [Examples](#examples) * [As an alias](#as-an-alias) * [As an executable](#as-an-executable) * [Usage](#usage) * [Documenting commands](#documenting-commands) * [Validating arguments](#validating-arguments) * [Parsing arguments](#parsing-arguments) * [Raw arguments](#raw-arguments) * [Completions](#completions) * [Nested subcommands](#nested-subcommands) * [Aliases](#aliases) * [Sharing code between scripts](#sharing-code-between-scripts) * [Caching](#caching) * [Migrating to Sub 2.x](#migrating-to-sub-2x) * [change --bin to --executable](#change---bin-to---executable) * [Usage comments](#usage-comments) * [Help, commands and completions](#help-commands-and-completions) * [Inspiration](#inspiration) <!-- vim-markdown-toc --> ## Key features - **Display help:** Display usage and documentation for scripts. - **Validate arguments:** Validate arguments to scripts based on documentation. - **Parse arguments:** Automatically parse arguments to scripts so `getopts` is not needed. - **Nested subcommands:** Supports nested directories for hierarchical command structures. - **Aliases:** Supports aliases for subcommands. - **Completions:** Supports auto completion of subcommands. - **Cross-platform:** Works on Linux and macOS. ## Demo [](https://asciinema.org/a/664235) ## Installation <details> <summary>Homebrew</summary> ```sh brew install juanibiapina/tap/sub ``` </details> <details> <summary>Nix with Flakes (install the `sub` binary)</summary> Add sub to your flake inputs: ```nix { inputs = { sub = { url = "github:juanibiapina/sub"; inputs.nixpkgs.follows = "nixpkgs"; # Optional }; }; # ... } ``` Then add it to your packages: ```nix { environment.systemPackages = with pkgs; [ inputs.sub.packages."${pkgs.system}".sub # ... ]; } ``` </details> <details> <summary>Nix with Flakes (including setup)</summary> This repository is a flake that exports a function `lib.${system}.mkSubDerivation`. This function creates a package for your cli that uses `sub` as the entry point and already includes the [Setup](#setup). For an example on how to use it, check out https://github.com/ggazzi/dev-cli-utils Thanks [@ggazzi](https://github.com/ggazzi) for writing this module. </details> ## Setup This section explains how to set up a CLI called `hat` using `sub`. ### Examples For a simple example, check out a [hello world](https://github.com/juanibiapina/sub/tree/master/examples/hello) project. For a complete example with lots of features, check out the [complete](https://github.com/juanibiapina/sub/tree/master/examples/complete) example project. ### As an alias The quickest way to get started with `sub` is to define an alias for your CLI in your shell: ```sh alias hat='sub --name hat --absolute /path/to/cli/root --' ``` Where `/path/to/cli/root` contains a `libexec` directory with executable scripts, for example: ``` . βββ libexec βββ user-script1 βββ user-script2 Β Β βββ user-script3 ``` ### As an executable A more reliable way is to use an executable script as the entry point. Given the following directory structure: ``` . βββ bin βΒ Β βββ hat βββ libexec βββ user-script1 βββ user-script2 Β Β βββ user-script3 ``` The entry point in `bin/hat` is then: ```sh #!/usr/bin/env bash sub --name hat --executable "${BASH_SOURCE[0]}" --relative ".." -- "$@" ``` The `--executable` argument tells `sub` where the CLI entry point is located. This will almost always be `${BASH_SOURCE[0]}`. The `--relative` argument tells `sub` how to find the root of the CLI starting from the CLI entry point. In the line above, just replace `hat` with the name of your CLI. ## Usage Once you have set up your CLI (we called it `hat`), you can get help by running: ```sh $ hat --help ``` ``` Usage: hat [OPTIONS] [commands_with_args]... Arguments: [commands_with_args]... Options: --usage Print usage -h, --help Print help --completions Print completions --commands Print subcommands --extension <extension> Filter subcommands by extension Available subcommands: user-script1 user-script2 user-script3 ``` To invoke a subcommand, use: ``` $ hat user-script1 ``` To get help for a command, use the built in `--help` flag: ```sh hat --help <commandname> ``` or ```sh hat <commandname> --help ``` ## Documenting commands In order to display help information, `sub` looks for special comments in the corresponding script. A fully documented `hello` script could look like this: ```sh #!/usr/bin/env bash # # Summary: Say hello # # Usage: {cmd} <name> [--spanish] # # Say hello to a user by name. # # With the --spanish flag, the greeting will be in Spanish. set -e declare -A args="($_HAT_ARGS)" if [[ "${args[spanish]}" == "true" ]]; then echo "Β‘Hola, ${args[name]}!" else echo "Hello, ${args[name]}!" fi ``` `sub` looks for special comments in a comment block in the beginning of the file. The special comments are: - `Summary:` A short description of the script. - `Usage:` A description of the arguments the script accepts. Note that the Usage comment, when present, has specific syntactic rules and is used to parse command line arguments. See [Validating arguments](#validating-arguments) and [Parsing arguments](#parsing-arguments) for more information. - `Options:` A description of the options the script accepts. This is used to display help information and generate completions. See [Completions](#completions) for more details. - Extended documentation: Any other comment lines in this initial block will be considered part of the extended documentation. ## Validating arguments `sub` automatically validates arguments to scripts based on the `Usage` comment when it is present. The syntax for the `Usage` comment is: ``` # Usage: {cmd} <positional> [optional] [-u] [--long] [--value=VALUE] [--exclusive]! [rest]... ``` - `{cmd}`: This special token represents the name of the command and is always required. - `<positional>`: A required positional argument. - `[optional]`: An optional positional argument. - `[-u]`: An optional short flag. - `[--long]`: An optional long flag. - `[--value=VALUE]`: An optional long flag that takes a value. - `[--exclusive]!`: An optional long flag that cannot be used with other flags. - `[rest]...`: A rest argument that consumes all remaining arguments. Short and long flags can also be made required by omitting the brackets. When invoking a script with invalid arguments, `sub` will display an error. For example, invoking the `hello` script from the previous section with invalid arguments: ```sh $ hat hello ``` ``` error: the following required arguments were not provided: <name> Usage: hat hello --spanish <name> For more information, try '--help'. ``` ## Parsing arguments When arguments to a script are valid, `sub` sets an environment variable called `_HAT_ARGS` (where `HAT` is the capitalized name of your CLI). This variable holds the parsed arguments as a list of key value pairs. The value of this variable is a string that can be evaluated to an associative array in bash scripts: ```sh declare -A args="($_HAT_ARGS)" ``` Which can then be used to access argument values: ```sh echo "${args[positional]}" if [[ "${args[long]}" == "true" ]]; then # ... fi ``` Every key and value in the variable is single quoted, so any argument value is safe to read this way. Quotes, `$`, backticks, newlines and globs are passed through literally and are never expanded or executed by the shell. Two things to keep in mind: - The idiom requires **bash 5.1 or later**. On bash 4.x it silently produces an empty array, bash 5.0 errors, and zsh cannot use it at all. - Arguments that accept multiple values (`[rest]...`, and the default `args` when a script has no `Usage` comment) are joined with a single space, so element boundaries are lost. Use `"$@"` when boundaries matter. ## Raw arguments Scripts always receive the original command line arguments unchanged, in the original order, as `"$@"`. `sub` runs the script directly, without a shell, and never rewrites argument values. Argument validation from the `Usage` comment still happens first, so a script only runs when its arguments are valid. ## Completions sub automatically provides completions for subcommand names. To enable completions for positional arguments in the `Usage` comment, add an `Options:` comment with a list of arguments. An option must have the format: `name (completion_type): description`. Completion type is optional. The following completion types are supported: - `` `command` ``: Runs a command to generate completions. The command should print completions to stdout: ```sh # Usage: {cmd} <file> # Options: # file (`ls -1`): File or directory # script logic # ... ``` - `script`: Invokes the current script to generate completions. This allows for more complex completions: ```sh # Usage: {cmd} <name> # Options: # name (script): A name # check if we're being requested completions if [[ "$_HAT_COMPLETE" == "true" ]]; then if [[ "$_HAT_COMPLETE_ARG" == "name" ]]; then echo "Alice" echo "Bob" echo "Charlie" # note that you can have any logic here to generate completions fi # make sure to exit when generating completions to prevent the script from running exit 0 fi # read arguments declare -A args="($_HAT_ARGS)" # say hello echo "Hello, ${args[name]}!" ``` ## Nested subcommands `sub` supports nested directories for hierarchical command structures. For example, given the following directory structure: ``` . βββ libexec βββ nested βββ README βββ user-script2 ``` `user-script2` can be invoked with: ```sh $ hat nested user-script2 ``` Directories can be nested arbitrarily deep. A `README` file can be placed in a directory to provide a description of the subcommands in that directory. The `README` file should be formatted like a script, with a special comment block at the beginning: ```sh # Summary: A collection of user scripts # # This directory contains scripts that do magic. # This help can be as long as you want. # The Usage comment is ignored in README files. ``` ## Aliases To define an alias, simply create a symlink. For example, in the `libexec` directory: ```sh ln -s user-script1 us1 ``` Aliases can also point to scripts in subdirectories: ```sh ln -s nested/user-script2 us2 ``` The full power of symlinks can be used to create complex command structures. ## Sharing code between scripts When invoking subcommands, `sub` sets an environment variable called `_HAT_ROOT` (where `HAT` is the capitalized name of your CLI. This variable holds the path to the root of your CLI. It can be used, for instance, for sourcing shared scripts from a `lib` directory next to `libexec`: ```sh source "$_CLINAME_ROOT/lib/shared.sh" ``` ## Caching When invoking subcommands, `sub` sets an environment variable called `_HAT_CACHE` (where `HAT` is the capitalized name of your CLI. This variable points to an XDG compliant cache directory that can be used for storing temporary files shared between subcommands. ## Migrating to Sub 2.x ### change --bin to --executable The `--bin` argument was renamed to `--executable` to better reflect its purpose. ### Usage comments Sub 2.x introduces automatic validation and parsing of command line arguments based on special Usage comments in scripts. If you previously used arbitrary Usage comments in sub 1.x for the purpose of documenting, you can run `sub` with the `--validate` flag to check if your scripts are compatible with the new version. Example: ``` $ sub --name hat --absolute /path/to/cli/root -- --validate ``` ### Help, commands and completions If you used the `help`, `commands` or `completions` subcommands, they are now `--help`, `--commands` and `--completions` flags respectively. ## Inspiration - [sub from basecamp](https://github.com/basecamp/sub) - [sd](https://github.com/cv/sd)