bash scripts

bash scripts

Code should be easy to read and understand.

The skill

- Code should be easy to read and understand.

- Keep the code as simple as possible. Avoid unnecessary complexity.

- Use meaningful names for variables, functions, etc. Names should reveal intent.

- Functions should be small and do one thing well. They should not exceed a few lines.

- Function names should describe the action being performed.

- Prefer fewer arguments in functions. Ideally, aim for no more than two or three.

- Only use comments when necessary, as they can become outdated.\
  Instead, strive to make the code self-explanatory.

- When comments are used, they should add useful information that is not\
  readily apparent from the code itself.

- Properly handle errors and exceptions to ensure the software's robustness.

- Consider security implications of the code.\
  Implement security best practices to protect against vulnerabilities and attacks.

- Executables must start with `#!/usr/bin/env bash` and minimal flags.

- Use set to set shell options so that calling your script as `bash script_name`\
  does not break its functionality.

- Shell should only be used for small utilities or simple wrapper scripts.

- If you are writing a script that is more than 100 lines long, or that uses\
  non-straightforward control flow logic, suggest a rewrite in a more\
  structured language now.

- Executables should have a .sh extension or no extension.

- Libraries must have a .sh extension and should not be executable.

- SUID and SGID are forbidden on shell scripts.

- All error messages should go to STDERR.

- Start each file with a description of its contents.

- Every file must have a top-level comment including a brief overview of its contents.

- A copyright notice and author information are optional.

- Any function that is not both obvious and short must have a function header comment.\
  Any function in a library must have a function header comment regardless of\
  length or complexity.

- It should be possible for someone else to learn how to use your program or\
  to use a function in your library by reading the comments (and self-help,\
  if provided) without reading the code.

- All function header comments should describe the intended API behaviour.

- Description of a function includes\
  `Globals: List of global variables used and modified`\
  `Arguments: Arguments taken`,`Outputs: Output to STDOUT or STDERR`\
  `Returns: Returned values other than the default exit status of last command`.

- Comment tricky, non-obvious, interesting or important parts of your code.

- Indent 2 spaces. No tabs.

- Maximum line length is 80 characters.

- If you have to write literal strings that are longer than 80 characters,\
  this should be done with a here document or an embedded newline if possible.

- Pipelines should be split one per line if they don’t all fit on one line.\
  If a pipeline all fits on one line, it should be on one line.

- Put `; then` and `; do` on the same line as the `if`, `for`, or `while`.

- `else` should be on its own line and closing statements (`fi` and `done`) should be\
  on their own line vertically aligned with the opening statement.

- Although it is possible to omit `in "$@"` in for loops we recommend consistently\
  including it for clarity.

- In case statements, indent alternatives by 2 spaces.\
  One-line alternatives need a space after the close parenthesis of the pattern\
  and before the `;;`\
  Long or multi-command alternatives should be split over \
  multiple lines with the pattern, actions, \
  and `;;` on separate lines.

- In order of precedence: Stay consistent with what you find;\
  quote your variables; prefer `"${var}"` over `"$var"`.

- Use `"$@"` unless you have a specific reason to use `"$*"`, such as simply\
  appending the arguments to a string in a message or log.

- Use `$(command)` instead of backticks.

- `[[…]]` is preferred over `[ … ]`, test and `/usr/bin/[`.

- Use quotes rather than filler characters where possible.

- Use an explicit path when doing wildcard expansion of filenames.

- `eval` should be avoided.

- Bash arrays should be used to store lists of elements, to avoid quoting\
  complications. This particularly applies to argument lists.

- Given the choice between invoking a shell builtin and invoking a separate process,\
  choose the builtin.

- Always check return values and give informative return values.

- A function called `main` is required for scripts long enough to contain\
  at least one other function.

- Put all functions together in the file just below constants.\
  Don’t hide executable code between functions.\
  Doing so makes the code difficult to follow and results in nasty surprises \
  when debugging.

- If you’ve got functions, put them all together near the top of the file.\
  Only includes, set statements and setting constants may be done\
  before declaring functions.

- Declare function-specific variables with local. Remenber that bash uses dynamic scoping i.e., local variables can be \
  accessed by called functions with the function's body.

- File names should be lowercase, with underscores to separate words if desired.

- Constants and anything exported to the environment should be capitalized,\
  separated with underscores, and declared at the top of the file.

- For the sake of clarity readonly or export is recommended\
  vs. the equivalent declare commands.

- Aliases should be avoided in scripts. Use functions instead.

- Always use `(( … ))` or `$(( … ))` rather than `let` or `$[ … ]` or `expr`.

- Use process substitution or the readarray builtin (bash4+) \
  in preference to piping to while.\
  Pipes create a subshell, so any variables modified within a pipeline\
  do not propagate to the parent shell.

- Function names should be lower-case, with underscores to separate words.\
  Separate libraries with `::`.\
  Parentheses are required after the function name.\
  The keyword function is optional, but must be used consistently throughout a project.

- Avoid modifying the values of the following bash variables in a script:\
  `BASH_VERSION`,`BASH_VERSINFO`,`EUID`, `UID`, `PPID`, `PID`, `PGID`, `SID`,\
  `SHLVL`, `RANDOM` ,`LINENO`, `FUNCNAME`, `BASH_SOURCE`, `BASH_LINENO`, `OSTYPE`,\
  `MACHTYPE`, `HOSTTYPE`,`HOSTNAME`,`LINES`, `COLUMNS`,`GROUPS`,`HOME`,`OPTARG`\
  ,`OPTIND`,`REPLY`, `SECONDS`,`TERM`, `DEBUG`.

- It's worth noting that Bash variables starting with an underscore \
  (e.g., `_`, `__`, etc.) are generally reserved for internal use and should not\
  be modified.

- When you have a function `main` in the script, wrap the call to `main` as below:

  ```bash
   if [[ "${BASH_SOURCE[0]}" == "${0}" ]];then
     main "$@"
    fi
  ```

- Every script must have a debug mode that can be enabled from the command line. It can be as simple as `set -x`.

- For a script that uses complex logic, it is a good practice to provide a dry-run \
  mode with the option enabled from the command line.

- Complex scripts must provide a verbose mode enabled using -v and --verbose from the command line. When verbose mode \
  is enabled, the script must provide detailed information about its execution, including any errors or warnings.

- When sourcing a file (say `include.sh`) for a script that may be executed from anywhere, use the following template:

  ```bash
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  source "$SCRIPT_DIR/include.sh"
  ```

- A script's usage must also include examples.

How to install it

1. Open the tool and start a new conversation, project or template.
2. Paste the text below wherever the tool keeps standing instructions
   — usually called system prompt, instructions, or persona.
3. Save it so it applies to every run rather than a single message.

Did it work for you?

Where it came from

Aider-AI contributors Apache-2.0 The original

[yyyy] [name of copyright owner]