|
| 1 | +## Creating ShellScript files |
| 2 | + |
| 3 | +When creating a ShellScript file: |
| 4 | + |
| 5 | +- Always include `./LICENSE` content as a comment at the end of the file. |
| 6 | + |
| 7 | +- Minimize dependencies on other ShellScript files whenever possible. |
| 8 | + - This is because `./README.md` explicitly states that the installation is independent of the environment. |
| 9 | + - However, exceptions are `./define-options.sh` and `./lib/fun.sh`, which may be depended upon. |
| 10 | + - This is also explicitly stated in `./README.md`. |
| 11 | + - For usage of `./lib/fun.sh`, refer to its contents or the [official README.md](https://raw.githubusercontent.com/ssledz/bash-fun/refs/heads/master/README.md). |
| 12 | + |
| 13 | +- If a library in the `./lib` directory seems useful, prioritize using it. |
| 14 | + - `./lib/fun.sh` is particularly useful. Keep functional programming in mind. |
| 15 | + |
| 16 | +- Include `#!/bin/bash` as the first line. |
| 17 | + |
| 18 | +- Follow this with a description and usage examples. For instance: |
| 19 | + - The usage examples should be comprehensive, but also remain simple and easy to read for users. |
| 20 | + |
| 21 | +bin/dust |
| 22 | +```sh |
| 23 | +#!/bin/bash |
| 24 | + |
| 25 | +# An alternative to `rm`, but moves the file to a dustbox instead. |
| 26 | +# |
| 27 | +# ```shell-session |
| 28 | +# $ ls README.md # Checking existence of readme |
| 29 | +# $ dust README.md |
| 30 | +# mv README.md /home/aiya000/.backup/dustbox/README.md_2025-02-25_13:45:37.md |
| 31 | +# ``` |
| 32 | + |
| 33 | +# Implementation follows |
| 34 | +# ... |
| 35 | + |
| 36 | +# Contents of ./LICENSE follow |
| 37 | +# ... |
| 38 | +``` |
| 39 | + |
| 40 | +- Read the "About `./sources`" and "About `./bin`" sections to determine the appropriate placement of ShellScript files. |
| 41 | + - Ensure that placed scripts adhere to the rules outlined in their respective sections. |
| 42 | + |
| 43 | +- Allow users as much configuration flexibility as possible. |
| 44 | + - Whenever possible, allow settings to be configured via environment variables. |
| 45 | + - In such cases, append the following format to `./define-options.sh`: |
| 46 | + |
| 47 | +define-options.sh |
| 48 | +```sh |
| 49 | +# ... |
| 50 | + |
| 51 | +[[ -z $BASH_TOYS_{VARIABLE_NAME} ]] && export BASH_TOYS_{VARIABLE_NAME}={DEFAULT_VALUE} |
| 52 | + |
| 53 | +# ... |
| 54 | +``` |
| 55 | + |
| 56 | +- After creating a ShellScript file, also create a corresponding test. |
| 57 | + - Test-related rules are outlined in the 'Creating Test Files' section. |
| 58 | + |
| 59 | +- When using variable names, prefer `$varname` over `${varname}`. |
| 60 | + - However, use `${varname}` when `$varname` could be misinterpreted as part of a string. |
| 61 | + |
| 62 | +- Always use `function` when defining functions. |
| 63 | +- When defining local variables within functions, use `local`. |
| 64 | +- Whenever possible, avoid using global variables (such as top-level `$1`) within functions and use arguments instead. |
| 65 | +- Strive for low module coupling and high module cohesion in functions. |
| 66 | + |
| 67 | +- While defining helper functions is acceptable, avoid excessive proliferation. |
| 68 | + - In other words, minimize unnecessary noise. |
| 69 | + |
| 70 | +Here are examples of unnecessary helper functions: |
| 71 | + |
| 72 | +```sh |
| 73 | +function has_glow () { |
| 74 | + # Writing this directly in the condition does not significantly reduce readability. |
| 75 | + command -v glow >/dev/null 2>&1 |
| 76 | +} |
| 77 | + |
| 78 | +function is_disable_glow_opt () { |
| 79 | + # Same as above. |
| 80 | + [[ $1 == '--disable-glow' ]] |
| 81 | +} |
| 82 | +``` |
| 83 | + |
| 84 | +Conversely, the following is an appropriate helper function: |
| 85 | + |
| 86 | +```sh |
| 87 | +# Show help |
| 88 | +function show_help () { |
| 89 | + cat << EOF |
| 90 | +bash-toys-help - Show help for bash-toys commands |
| 91 | + |
| 92 | +Usage: |
| 93 | + bash-toys-help [--disable-glow] COMMAND |
| 94 | + bash-toys-help --help |
| 95 | + |
| 96 | +Options: |
| 97 | + --disable-glow Do not use glow for markdown rendering |
| 98 | + --help Show this help message |
| 99 | +EOF |
| 100 | +} |
| 101 | +``` |
| 102 | + |
| 103 | +- Use `snake_case` for helper function names. |
| 104 | + - However, an exception applies to functions placed in `./sources` following the `function {feature_name}` naming pattern. |
| 105 | + - See the "About `./sources`" section for details. |
| 106 | + |
| 107 | +- Insert spaces before and after `;`. |
| 108 | +- Use `[[ ... ]]` instead of `[ ... ]`. |
| 109 | + |
| 110 | +- If `--help` is passed, implement it to display help documentation. |
| 111 | + - Ensure no other operations are performed when displaying help. |
| 112 | + |
| 113 | +- Prefer `''` over `""` when possible. |
| 114 | +- If quotes are unnecessary, omit them entirely. |
| 115 | + |
| 116 | +- While comments are allowed, avoid writing them if the code is self-explanatory. |
| 117 | + - Strive for code that is inherently descriptive. |
| 118 | + |
| 119 | +Here is an example where a comment is unnecessary: |
| 120 | +`# Show help` is redundant. |
| 121 | + |
| 122 | +```sh |
| 123 | +# Show help |
| 124 | +function show_help () { |
| 125 | + cat << EOF |
| 126 | +cmd - ... |
| 127 | + |
| 128 | +Usage: |
| 129 | + ... |
| 130 | + |
| 131 | +Options: |
| 132 | + ... |
| 133 | +EOF |
| 134 | +} |
| 135 | +``` |
| 136 | + |
| 137 | +- Run shellcheck and fix any issues whenever possible. |
| 138 | + |
| 139 | +### About `./sources` |
| 140 | + |
| 141 | +- ShellScripts that cannot be executed as a subprocess (i.e., functions affecting the current shell) should be placed in `./sources`. |
| 142 | + - Name the file `{feature_name}.sh` and define a function inside it as `function {feature_name} () { ... }`. |
| 143 | + - Use `kebab-case` for `{feature_name}`. |
| 144 | + |
| 145 | +For example: |
| 146 | + |
| 147 | +source/define-alias.sh |
| 148 | +```sh |
| 149 | +#!/bin/bash |
| 150 | + |
| 151 | +# Defines an alias. |
| 152 | +# ```shell-session |
| 153 | +# $ define-alias ll 'ls -l' |
| 154 | +# ``` |
| 155 | + |
| 156 | +function define-alias () { |
| 157 | + local name=$1 detail=$2 |
| 158 | + eval "alias $name='$detail'" |
| 159 | +} |
| 160 | +``` |
| 161 | + |
| 162 | +- All other ShellScripts that can be executed as a subprocess should be placed in `./bin`. |
| 163 | + |
| 164 | +### About `./bin` |
| 165 | + |
| 166 | +- ShellScripts that can be executed as a subprocess should be placed in `./bin`. |
| 167 | + - Name the file `{feature_name}` without an extension. |
| 168 | + |
| 169 | +Refer to the "About `./sources`" section for additional details. |
| 170 | + |
| 171 | +## Git |
| 172 | + |
| 173 | +- Write commit messages in English. |
| 174 | + |
| 175 | +- Format commit messages as `{Verb} ...`. |
| 176 | + - Capitalize the first letter of the verb, e.g., `Add ...`, `Fix ...`. |
| 177 | + |
| 178 | +- If the `gh` command is available, check the issue list using `$ gh issue list` before committing. |
| 179 | + - If there is an issue that the commit is likely to resolve, add `Closes #{IssueNumber}` on the third line of the commit message. |
| 180 | + |
| 181 | +## General Rules |
| 182 | + |
| 183 | +- When executing `$ curl {url} | sh` or `$ curl {url} | bash`, always review the contents of `{url}` first and understand any potential risks before proceeding. |
| 184 | + - If any risks exist, halt the process and consult with me for further instructions. |
| 185 | + |
| 186 | +- If installing OS packages (e.g., `$ sudo apt install {packages}` or `$ brew install {packages}`) is necessary, pause the task and consult with me first. |
0 commit comments