| name | script-best-practices |
| description | Applies shell script best practices when writing or modifying Bash or shell scripts. Use for executable scripts, shell libraries, CI scripts, install scripts, dotfile scripts, and shell command snippets. |
Script Best Practices
Use this skill when writing or modifying shell scripts, especially Bash scripts.
Default to the repository's conventions. Make small, readable changes. Do not rewrite working scripts only to satisfy style preferences.
This guidance comes from Google's Shell Style Guide: https://google.github.io/styleguide/shellguide.html
When to use shell
- Use shell for small utilities, wrappers, glue code, and simple automation.
- Use another language when logic becomes complex, data structures become non-trivial, parsing is subtle, or robust error handling matters.
- Prefer builtins and direct shell constructs over clever pipelines.
Interpreter and file shape
- For executable Bash scripts, use
#!/bin/bash unless the repository requires another interpreter.
- Set shell options with
set instead of shebang flags so bash script_name behaves like direct execution.
- Use
.sh or no extension for executables. Use .sh for shell libraries, and do not make libraries executable.
- Never use SUID or SGID shell scripts. Use
sudo or another controlled privilege boundary for elevated access.
- Start each file with a brief comment describing what it does.
- Put constants near the top, then functions, then executable code.
- If a script has functions, put program entry in
main, make main the bottom-most function, and call main "$@" as the last non-comment line.
Formatting
Naming and scope
Quoting and expansion
- Quote variables by default.
- Prefer
"${var}" over "$var" for regular variables.
- Remember that braces are not quoting. Use
"${var}", not just ${var}.
- Use
"$@" when forwarding arguments. Avoid $* and unquoted $@.
- Use arrays for lists and command arguments, then expand them with
"${array[@]}".
- Do not store multiple command arguments in one string.
- Use
$(command) instead of backticks.
- Use explicit paths for wildcard expansion, for example
./* instead of *, so filenames beginning with - do not become options.
Tests and conditionals
- Prefer
[[ ... ]] over [ ... ] or test in Bash.
- Use
-z and -n for empty and non-empty string checks.
- Use
== for string equality inside [[ ... ]].
- Use
(( ... )) or $(( ... )) for arithmetic. Avoid let, $[ ... ], and expr.
- Do not use
< or > inside [[ ... ]] for numeric comparison. They are lexicographic there.
- In
[[ string =~ regex ]], quote variables, but do not quote the regex pattern when pattern semantics are intended.
Error handling and output
Common footguns
Comments and documentation
- Comment tricky, non-obvious, security-sensitive, or compatibility-sensitive behavior.
- Do not comment every command.
- For non-trivial functions, document purpose, globals, arguments, outputs, and return behavior.
- Include an owner or identifier in TODO comments, for example
# TODO(matteo): ....
Before finishing